From ba4294ae0c06c1ed160f0be47863c9515da8d403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 23 Jun 2014 18:05:06 +0200 Subject: [PATCH 01/55] saving current state --- bin/style.js | 3768 +-------------------- common/glfw_view.cpp | 9 +- include/llmr/geometry/buffer.hpp | 4 + include/llmr/map/map.hpp | 15 +- include/llmr/map/raster_tile_data.hpp | 4 +- include/llmr/map/source.hpp | 53 +- include/llmr/map/tile_data.hpp | 6 +- include/llmr/map/tile_parser.hpp | 26 +- include/llmr/map/vector_tile.hpp | 4 +- include/llmr/map/vector_tile_data.hpp | 4 +- include/llmr/renderer/bucket.hpp | 3 +- include/llmr/renderer/debug_bucket.hpp | 2 +- include/llmr/renderer/fill_bucket.hpp | 6 +- include/llmr/renderer/icon_bucket.hpp | 6 +- include/llmr/renderer/line_bucket.hpp | 6 +- include/llmr/renderer/painter.hpp | 21 +- include/llmr/renderer/raster_bucket.hpp | 2 +- include/llmr/renderer/text_bucket.hpp | 6 +- include/llmr/style/bucket_description.hpp | 120 +- include/llmr/style/layer_description.hpp | 22 +- include/llmr/style/properties.hpp | 371 +- include/llmr/style/style.hpp | 152 +- include/llmr/style/style_bucket.hpp | 82 + include/llmr/style/style_parser.hpp | 99 +- include/llmr/style/types.hpp | 136 + include/llmr/text/glyph.hpp | 2 +- include/llmr/text/placement.hpp | 4 +- llmr.gyp | 2 +- src/map/map.cpp | 227 +- src/map/raster_tile_data.cpp | 8 +- src/map/source.cpp | 100 +- src/map/tile_parser.cpp | 157 +- src/map/vector_tile.cpp | 17 +- src/map/vector_tile_data.cpp | 34 +- src/renderer/debug_bucket.cpp | 2 +- src/renderer/fill_bucket.cpp | 6 +- src/renderer/icon_bucket.cpp | 6 +- src/renderer/line_bucket.cpp | 6 +- src/renderer/painter.cpp | 8 +- src/renderer/painter_clipping.cpp | 21 +- src/renderer/painter_debug.cpp | 33 +- src/renderer/painter_fill.cpp | 103 +- src/renderer/painter_framebuffers.cpp | 2 +- src/renderer/painter_icon.cpp | 21 +- src/renderer/painter_line.cpp | 9 +- src/renderer/painter_prerender.cpp | 36 +- src/renderer/painter_raster.cpp | 9 +- src/renderer/painter_text.cpp | 26 +- src/renderer/raster_bucket.cpp | 4 +- src/renderer/text_bucket.cpp | 6 +- src/style/layer_description.cpp | 34 +- src/style/properties.cpp | 13 +- src/style/style.cpp | 2144 ++++++------ src/style/style_parser.cpp | 1330 ++++---- src/text/glyph.cpp | 2 +- src/text/placement.cpp | 2 +- 56 files changed, 3078 insertions(+), 6223 deletions(-) create mode 100644 include/llmr/style/style_bucket.hpp create mode 100644 include/llmr/style/types.hpp 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); From ff571fabcfe967b503358689359398678571d4d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Tue, 24 Jun 2014 11:39:16 +0200 Subject: [PATCH 02/55] fix exit crash due to forced loop stop --- src/map/map.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/map/map.cpp b/src/map/map.cpp index a77e9d0c5..294dca4b8 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -76,13 +76,6 @@ void Map::stop() { uv_thread_join(&thread); - uv_close((uv_handle_t *)async_terminate, delete_async); - async_terminate = nullptr; - uv_close((uv_handle_t *)async_render, delete_async); - async_render = nullptr; - uv_close((uv_handle_t *)async_cleanup, delete_async); - async_cleanup = nullptr; - // Run the event loop once to make sure our async delete handlers are called. uv_run(**loop, UV_RUN_ONCE); @@ -161,7 +154,13 @@ void Map::render(uv_async_t *async) { } void Map::terminate(uv_async_t *async) { - uv_stop(static_cast(async->data)); + // Closes all open handles on the loop. This means that the loop will automatically terminate. + uv_loop_t *loop = static_cast(async->data); + uv_walk(loop, [](uv_handle_t *handle, void *arg) { + if (!uv_is_closing(handle)) { + uv_close(handle, NULL); + } + }, NULL); } #pragma mark - Setup From a1e40c1780e479abe6b8843d5058d7768538d548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Tue, 24 Jun 2014 13:45:14 +0200 Subject: [PATCH 03/55] change enum parsing --- include/llmr/renderer/painter.hpp | 2 +- include/llmr/style/properties.hpp | 6 +- include/llmr/style/style_bucket.hpp | 12 +-- include/llmr/style/types.hpp | 132 ++++++++++++++-------------- 4 files changed, 76 insertions(+), 76 deletions(-) diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index 1adca7045..1b1d231ca 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -114,7 +114,7 @@ public: bool needsAnimation() const; private: void setupShaders(); - const mat4 &translatedMatrix(const std::array &translation, const Tile::ID &id, TranslateAnchorType anchor = parseTranslateAnchorType()); + const mat4 &translatedMatrix(const std::array &translation, const Tile::ID &id, TranslateAnchorType anchor = TranslateAnchorType::Default); void prepareTile(const Tile& tile); diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index cc85122a2..644fd34cc 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -228,7 +228,7 @@ struct FillProperties { Color fill_color = {{ 0, 0, 0, 1 }}; Color stroke_color = {{ 0, 0, 0, 1 }}; std::array translate = {{ 0, 0 }}; - TranslateAnchorType translateAnchor = parseTranslateAnchorType(); + TranslateAnchorType translateAnchor = TranslateAnchorType::Default; std::string image; inline bool isVisible() const { @@ -242,7 +242,7 @@ struct LineProperties { float opacity = 1.0f; Color color = {{ 0, 0, 0, 1 }}; std::array translate = {{ 0, 0 }}; - TranslateAnchorType translateAnchor = parseTranslateAnchorType(); + TranslateAnchorType translateAnchor = TranslateAnchorType::Default; float width = 0; float offset = 0; float blur = 0; @@ -259,7 +259,7 @@ struct IconProperties { bool enabled = true; float opacity = 1.0f; float rotate = 0.0f; - RotateAnchorType rotate_anchor = parseRotateAnchorType(); + RotateAnchorType rotate_anchor = RotateAnchorType::Default; inline bool isVisible() const { return enabled && opacity > 0; diff --git a/include/llmr/style/style_bucket.hpp b/include/llmr/style/style_bucket.hpp index f39ea0161..f6c946ac0 100644 --- a/include/llmr/style/style_bucket.hpp +++ b/include/llmr/style/style_bucket.hpp @@ -12,13 +12,13 @@ class Source; class StyleBucketFill { public: - WindingType winding = parseWindingType(); + WindingType winding = WindingType::Default; }; class StyleBucketLine { public: - CapType cap = parseCapType(); - JoinType join = parseJoinType(); + CapType cap = CapType::Default; + JoinType join = JoinType::Default; float miter_limit = 2.0f; float round_limit = 1.0f; }; @@ -27,7 +27,7 @@ class StyleBucketIcon { public: uint16_t size = 16; vec2 translate {0, 0}; - TranslateAnchorType translate_anchor = parseTranslateAnchorType(); + TranslateAnchorType translate_anchor = TranslateAnchorType::Default; std::string icon; float spacing = 0.0f; float padding = 2.0f; @@ -36,7 +36,7 @@ public: class StyleBucketText { public: std::string field; - TextPathType path = parseTextPathType(); + TextPathType path = TextPathType::Default; std::string font; float max_size = 16.0f; float max_width = 15.0f * 24; @@ -45,7 +45,7 @@ public: float alignment = 0.5f; float vertical_alignment = 0.5; vec2 translate {0, 0}; - TranslateAnchorType translate_anchor = parseTranslateAnchorType(); + TranslateAnchorType translate_anchor = TranslateAnchorType::Default; float max_angle_delta = M_PI; float min_distance = 250.0f; float rotate = 0.0f; // what is this? diff --git a/include/llmr/style/types.hpp b/include/llmr/style/types.hpp index 0d1061d5d..9bd84d142 100644 --- a/include/llmr/style/types.hpp +++ b/include/llmr/style/types.hpp @@ -11,124 +11,124 @@ enum class BucketType : uint8_t { Line, Icon, Text, - Raster + Raster, + Default = None }; enum class WindingType : uint8_t { EvenOdd, - NonZero + NonZero, + Default = NonZero }; enum class CapType : uint8_t { None, Round, Butt, - Square + Square, + Default = None }; enum class JoinType : uint8_t { None, Miter, Bevel, - Round + Round, + Default = None }; enum class TextPathType : uint8_t { Horizontal, - Curve + Curve, + Default = Horizontal }; enum class TranslateAnchorType : uint8_t { Map, - Viewport + Viewport, + Default = Map }; enum class RotateAnchorType : uint8_t { Map, - Viewport + Viewport, + Default = Viewport }; enum class SourceType : uint8_t { Vector, Raster, GeoJSON, - Video + Video, + Default = Vector }; -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 BucketType parseBucketType(const std::string &type) { + if (type == "fill") return BucketType::Fill; + if (type == "line") return BucketType::Line; + if (type == "icon") return BucketType::Icon; + if (type == "text") return BucketType::Text; + if (type == "raster") return BucketType::Raster; + return BucketType::None; } -inline constexpr WindingType parseWindingType(const std::string &type = "") { - return - type.compare("even-odd") == 0 ? WindingType::EvenOdd : - WindingType::NonZero; +inline WindingType parseWindingType(const std::string &type) { + if (type == "even-odd") return WindingType::EvenOdd; + if (type == "non-zero") return WindingType::NonZero; + return WindingType::Default; } -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 CapType parseCapType(const std::string &cap) { + if (cap == "round") return CapType::Round; + if (cap == "butt") return CapType::Butt; + if (cap == "square") return CapType::Square; + return CapType::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 JoinType parseJoinType(const std::string &join) { + if (join == "miter") return JoinType::Miter; + if (join == "bevel") return JoinType::Bevel; + if (join == "round") return JoinType::Round; + return JoinType::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 TextPathType parseTextPathType(const std::string &path) { + if (path == "horizontal") return TextPathType::Horizontal; + if (path == "curve") return TextPathType::Curve; + return TextPathType::Default; } -inline constexpr TranslateAnchorType parseTranslateAnchorType(const std::string &anchor = "") { - return - anchor.compare("viewport") == 0 ? TranslateAnchorType::Viewport : - TranslateAnchorType::Map; +inline TranslateAnchorType parseTranslateAnchorType(const std::string &anchor) { + if (anchor == "map") return TranslateAnchorType::Map; + if (anchor == "viewport") return TranslateAnchorType::Viewport; + return TranslateAnchorType::Default; } -inline constexpr RotateAnchorType parseRotateAnchorType(const std::string &anchor = "") { - return - anchor.compare("map") == 0 ? RotateAnchorType::Map : - RotateAnchorType::Viewport; +inline RotateAnchorType parseRotateAnchorType(const std::string &anchor) { + if (anchor == "map") return RotateAnchorType::Map; + if (anchor == "viewport") return RotateAnchorType::Viewport; + return RotateAnchorType::Default; } -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; +inline float parseAlignmentType(const std::string &alignment) { + if (alignment == "right") return 1.0f; + if (alignment == "left") return 0.0f; + return 0.5f; } +inline float parseVerticalAlignmentType(const std::string &alignment) { + if (alignment == "bottom") return 1.0f; + if (alignment == "top") return 0.0f; + return 0.5f; +} + +inline SourceType parseSourceType(const std::string &source) { + if (source == "vector") return SourceType::Vector; + if (source == "raster") return SourceType::Raster; + if (source == "geojson") return SourceType::GeoJSON; + if (source == "video") return SourceType::Video; + return SourceType::Default; +} } From b72583371ccaefc1c99992c873c2f6b6c695b39a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Tue, 24 Jun 2014 14:10:00 +0200 Subject: [PATCH 04/55] add memory header --- include/llmr/style/style_bucket.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/llmr/style/style_bucket.hpp b/include/llmr/style/style_bucket.hpp index f6c946ac0..bd6dcf714 100644 --- a/include/llmr/style/style_bucket.hpp +++ b/include/llmr/style/style_bucket.hpp @@ -6,6 +6,8 @@ #include #include +#include + namespace llmr { class Source; From 7637b7f8c75af0af35ada4bc989b61d188db4f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Tue, 24 Jun 2014 16:47:11 +0200 Subject: [PATCH 05/55] get applied classes --- include/llmr/map/map.hpp | 3 +-- include/llmr/style/style.hpp | 1 + src/map/map.cpp | 8 ++++---- src/style/style.cpp | 4 ++++ 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index ee5debe4d..2c412bd45 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -52,8 +52,7 @@ public: // Styling void toggleClass(const std::string &name); -// void setAppliedClasses(const std::vector &appliedClasses); -// const std::vector &getAppliedClasses() const; + const std::vector &getAppliedClasses() const; void setDefaultTransitionDuration(uint64_t duration_milliseconds = 0); void setStyleJSON(std::string newStyleJSON); std::string getStyleJSON() const; diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index d4b5a7961..1c4cf11d4 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -71,6 +71,7 @@ public: void updateSources(); const std::set> getActiveSources() const; + const std::vector &getAppliedClasses() const; void toggleClass(const std::string &name); public: diff --git a/src/map/map.cpp b/src/map/map.cpp index 294dca4b8..01f7ac607 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -390,10 +390,10 @@ void Map::toggleClass(const std::string &name) { // // update(); //} -// -//const std::vector &Map::getAppliedClasses() const { -// return style->appliedClasses; -//} + +const std::vector &Map::getAppliedClasses() const { + return style->getAppliedClasses(); +} void Map::setDefaultTransitionDuration(uint64_t duration_milliseconds) { style->setDefaultTransitionDuration(duration_milliseconds); diff --git a/src/style/style.cpp b/src/style/style.cpp index 3bb494867..264cef0b6 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -1229,6 +1229,10 @@ void Style::setDefaultTransitionDuration(uint64_t duration_milliseconds) { default_transition_duration = duration_milliseconds; } +const std::vector &Style::getAppliedClasses() const { + return appliedClasses; +} + void Style::toggleClass(const std::string &name) { if (name.length()) { auto it = std::find(appliedClasses.begin(), appliedClasses.end(), name); From eb84492556901ac6c6a77c141ac5e37dba70a40c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Tue, 24 Jun 2014 16:47:55 +0200 Subject: [PATCH 06/55] paint background when clearing --- src/renderer/painter.cpp | 10 ++++------ src/renderer/painter_clipping.cpp | 7 ++----- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 9d11fe108..0739eea32 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -135,13 +135,11 @@ void Painter::clear() { gl::group group("clear"); glStencilMask(0xFF); depthMask(true); -#ifdef NVIDIA - // We're painting in a way that allows us to skip clearing the color buffer. - // On Tegra hardware, this is faster. - glClear(GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -#else + + std::shared_ptr background_layer = map.getStyle()->background; + const BackgroundProperties &properties = background_layer ? background_layer->getProperties() : defaultStyleProperties(); + glClearColor(properties.color[0], properties.color[1], properties.color[2], properties.color[3]); glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -#endif } void Painter::setOpaque() { diff --git a/src/renderer/painter_clipping.cpp b/src/renderer/painter_clipping.cpp index 18f546664..95e4b727f 100644 --- a/src/renderer/painter_clipping.cpp +++ b/src/renderer/painter_clipping.cpp @@ -12,14 +12,10 @@ void Painter::drawClippingMasks(const std::set> &sources useProgram(plainShader->program); glDisable(GL_DEPTH_TEST); depthMask(false); + glColorMask(false, false, false, false); glDepthRange(1.0f, 1.0f); glStencilMask(0xFF); -// 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 std::shared_ptr &source : sources) { @@ -27,6 +23,7 @@ void Painter::drawClippingMasks(const std::set> &sources } glEnable(GL_DEPTH_TEST); + glColorMask(true, true, true, true); depthMask(true); glStencilMask(0x0); } From 79643d973a15dd82ce509907707ac67034354c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Tue, 24 Jun 2014 19:01:12 +0200 Subject: [PATCH 07/55] fix matrices --- src/renderer/painter_icon.cpp | 2 +- src/renderer/painter_text.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/painter_icon.cpp b/src/renderer/painter_icon.cpp index 3ea104887..f720a2400 100644 --- a/src/renderer/painter_icon.cpp +++ b/src/renderer/painter_icon.cpp @@ -20,7 +20,7 @@ void Painter::renderIcon(IconBucket& bucket, std::shared_ptr layer_d SpriteAtlas &spriteAtlas = *map.getSpriteAtlas(); useProgram(iconShader->program); - iconShader->setMatrix(vtxMatrix); + iconShader->setMatrix(matrix); // TODO: update // iconShader->setColor(color); iconShader->setImage(0); diff --git a/src/renderer/painter_text.cpp b/src/renderer/painter_text.cpp index cc5acbcab..40a4edf89 100644 --- a/src/renderer/painter_text.cpp +++ b/src/renderer/painter_text.cpp @@ -28,7 +28,7 @@ void Painter::renderText(TextBucket& bucket, std::shared_ptr layer_d // const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor); useProgram(textShader->program); - textShader->setMatrix(vtxMatrix); + textShader->setMatrix(matrix); textShader->setExtrudeMatrix(exMatrix); GlyphAtlas &glyphAtlas = *map.getGlyphAtlas(); From b95d023a9803f68b4f7abfba1d66ca0045c946b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Tue, 24 Jun 2014 19:01:41 +0200 Subject: [PATCH 08/55] remove debug statements --- src/map/tile_parser.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index b31d1383e..b4041ada4 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -108,19 +108,14 @@ std::unique_ptr TileParser::createBucket(std::shared_ptr bu if (layer_it != vector_data.layers.end()) { const VectorTileLayer &layer = layer_it->second; 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 { fprintf(stderr, "[WARNING] unknown bucket render type for layer '%s'\n", bucket_desc->source_layer.c_str()); From aff667d7427ba341edb93386d2b6690aa8aa0a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 26 Jun 2014 15:04:18 +0200 Subject: [PATCH 09/55] add filter expressions --- include/llmr/map/filter_expression.hpp | 189 +++++---- include/llmr/map/tile_parser.hpp | 12 +- include/llmr/map/vector_tile.hpp | 25 +- include/llmr/style/bucket_description.hpp | 2 +- include/llmr/style/style_bucket.hpp | 3 +- include/llmr/style/style_parser.hpp | 9 +- include/llmr/style/value.hpp | 12 +- include/llmr/util/recursive_wrapper.hpp | 31 +- include/llmr/util/variant.hpp | 463 ++++++++++++++++------ src/map/filter_expression.cpp | 282 +++++++++++++ src/map/map.cpp | 2 - src/map/tile_parser.cpp | 18 +- src/map/vector_tile.cpp | 201 ++++++---- src/style/style_parser.cpp | 165 ++++---- 14 files changed, 984 insertions(+), 430 deletions(-) create mode 100644 src/map/filter_expression.cpp diff --git a/include/llmr/map/filter_expression.hpp b/include/llmr/map/filter_expression.hpp index 50e6ce1d7..3c4ac857e 100644 --- a/include/llmr/map/filter_expression.hpp +++ b/include/llmr/map/filter_expression.hpp @@ -4,125 +4,114 @@ #include #include -#include +#include #include +#include +#include namespace llmr { -enum class FilterOperator { - Equal, - NotEqual, - Greater, - GreaterEqual, - Less, - LessEqual -}; +class VectorTileTagExtractor; -enum class ExpressionOperator { - Or, - And -}; - - -inline FilterOperator filterOperatorType(const std::string &op) { - if (op == "!=" || op == "not") { - return FilterOperator::NotEqual; - } else if (op == "==" || op == "eq") { - return FilterOperator::Equal; - } else if (op == ">" || op == "gt") { - return FilterOperator::Greater; - } else if (op == ">=" || op == "gte") { - return FilterOperator::GreaterEqual; - } else if (op == "<" || op == "lt") { - return FilterOperator::Less; - } else if (op == "<=" || op == "lte") { - return FilterOperator::LessEqual; - } else { - fprintf(stderr, "[WARNING] filter operator '%s' unrecognized\n", op.c_str()); - return FilterOperator::Equal; - } -} - -inline ExpressionOperator expressionOperatorType(const std::string &op) { - if (op == "&&" || op == "and") { - return ExpressionOperator::And; - } else if (op == "||" || op == "or") { - return ExpressionOperator::Or; - } else { - fprintf(stderr, "[WARNING] expression operator '%s' unrecognized\n", op.c_str()); - return ExpressionOperator::Or; - } -} - - -class PropertyFilter; -class PropertyExpression; - -typedef util::variant< - util::recursive_wrapper, - util::recursive_wrapper, - std::true_type -> PropertyFilterExpression; - - -class PropertyFilter { +class FilterComparison { public: - inline PropertyFilter(const std::string &field, FilterOperator op, const Value &value) : field(field), op(op), value(value) {}; - inline PropertyFilter(PropertyFilter &&filter) - : field(std::move(filter.field)), - op(filter.op), - value(std::move(filter.value)) { - } + enum class Operator : uint8_t { + Equal, + NotEqual, + Greater, + GreaterEqual, + Less, + LessEqual, + In, + NotIn + }; - // Returns true if the filter passes, even if the key is missing. - inline bool isMissingFieldOkay() const { - switch (op) { - case FilterOperator::NotEqual: - return true; - default: - return false; - } - } + class Instance { + public: + Instance(Operator op, std::forward_list &&values) + : op(op), values(values) {} - inline bool compare(const Value &other) const { - switch (op) { - case FilterOperator::Equal: - return util::relaxed_equal(other, value); - case FilterOperator::NotEqual: - return !util::relaxed_equal(other, value); - case FilterOperator::Greater: - return util::relaxed_greater(other, value); - case FilterOperator::GreaterEqual: - return util::relaxed_greater_equal(other, value); - case FilterOperator::Less: - return util::relaxed_less(other, value); - case FilterOperator::LessEqual: - return util::relaxed_less_equal(other, value); - default: - return false; - } - } + bool compare(const Value &property_value) const; + bool compare(const std::forward_list &property_values) const; + + private: + template inline bool includes(const Value &property_value, const Comparer &comparer) const; + template inline bool compare(const Value &property_value, const Comparer &comparer) const; + template inline bool all(const std::forward_list &property_values, const Comparer &comparer) const; + + private: + Operator op = Operator::Equal; + std::forward_list values; + + friend std::ostream& operator <<(std::ostream &, const Instance &); + }; public: + FilterComparison(const std::string &field) : field(field) {}; + + const std::string &getField() const; + inline bool compare(const VectorTileTagExtractor &extractor) const; + + template + inline void add(Args&& ...args) { + instances.emplace_front(::std::forward(args)...); + } + +private: std::string field; - FilterOperator op = FilterOperator::Equal; - Value value; + std::forward_list instances; + + friend std::ostream& operator <<(std::ostream &, const FilterComparison &); }; -class PropertyExpression { +std::ostream& operator <<(std::ostream &s, const FilterComparison &comparison); +std::ostream& operator <<(std::ostream &s, const FilterComparison::Instance &instance); + + +FilterComparison::Operator parseFilterComparisonOperator(const std::string &op); + + +class FilterExpression { public: - inline PropertyExpression() {} - inline PropertyExpression(PropertyExpression &&expression) - : op(expression.op), - operands(std::move(expression.operands)) { - } + typedef util::recursive_wrapper Wrapper; + + enum class Operator : uint8_t { + And, + Or, + Xor, + Nor + }; + + enum class GeometryType : uint8_t { + Any, + Point, + Line, + Polygon + }; public: - ExpressionOperator op = ExpressionOperator::Or; - std::vector operands; + FilterExpression() = default; + FilterExpression(Operator op) : op(op) {}; + + bool empty() const; + + bool compare(const VectorTileTagExtractor &extractor) const; + void add(const FilterComparison &comparison); + void add(const FilterExpression &expression); + void setGeometryType(GeometryType g); + +private: + Operator op = Operator::And; + GeometryType type = GeometryType::Any; + std::forward_list comparisons; + std::forward_list expressions; + + friend std::ostream& operator <<(std::ostream &, const FilterExpression &); }; +std::ostream& operator <<(std::ostream &s, const FilterExpression &expression); +FilterExpression::GeometryType parseGeometryType(const std::string &geometry); } #endif diff --git a/include/llmr/map/tile_parser.hpp b/include/llmr/map/tile_parser.hpp index 9e763a13a..2809c6b4e 100644 --- a/include/llmr/map/tile_parser.hpp +++ b/include/llmr/map/tile_parser.hpp @@ -42,13 +42,13 @@ private: void addGlyph(uint64_t tileid, const std::string stackname, const std::u32string &string, const FontStack &fontStack, GlyphAtlas &glyphAtlas, GlyphPositions &face); 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); + std::unique_ptr createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill); + std::unique_ptr createLineBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketLine &line); + std::unique_ptr createIconBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketIcon &icon); + std::unique_ptr createTextBucket(const VectorTileLayer& layer, const FilterExpression &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); + template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter); + template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &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 b2f3d416e..f9e01c38b 100644 --- a/include/llmr/map/vector_tile.hpp +++ b/include/llmr/map/vector_tile.hpp @@ -40,6 +40,22 @@ public: std::ostream& operator<<(std::ostream&, const VectorTileFeature& feature); + +class VectorTileTagExtractor { +public: + VectorTileTagExtractor(const VectorTileLayer &layer); + + void setTags(const pbf &pbf); + std::forward_list getValues(const std::string &key) const; + void setType(FilterExpression::GeometryType type); + FilterExpression::GeometryType getType() const; + +private: + const VectorTileLayer &layer_; + pbf tags_; + FilterExpression::GeometryType type_ = FilterExpression::GeometryType::Any; +}; + /* * Allows iterating over the features of a VectorTileLayer using a * BucketDescription as filter. Only features matching the descriptions will @@ -54,11 +70,6 @@ public: bool operator!=(const iterator& other) const; const pbf& operator*() const; - private: - bool matchesFilterExpression(const PropertyFilterExpression &filterExpression, const pbf &tags_pbf); - bool matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf); - bool matchesFilter(const PropertyFilter &filter, const pbf &tags_pbf); - private: const FilteredVectorTileLayer& parent; bool valid = false; @@ -67,14 +78,14 @@ public: }; public: - FilteredVectorTileLayer(const VectorTileLayer& layer, const PropertyFilterExpression &filterExpression); + FilteredVectorTileLayer(const VectorTileLayer& layer, const FilterExpression &filterExpression); iterator begin() const; iterator end() const; private: const VectorTileLayer& layer; - const PropertyFilterExpression& filterExpression; + const FilterExpression& filterExpression; }; std::ostream& operator<<(std::ostream&, const GlyphPlacement& placement); diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index 9b1bb5c77..6011b5399 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -22,7 +22,7 @@ public: std::string source_name; std::string source_layer; - PropertyFilterExpression filter = std::true_type(); + FilterExpression filter; // Specifies how the geometry for this bucket should be created StyleBucketRender render; diff --git a/include/llmr/style/style_bucket.hpp b/include/llmr/style/style_bucket.hpp index bd6dcf714..eee9929a8 100644 --- a/include/llmr/style/style_bucket.hpp +++ b/include/llmr/style/style_bucket.hpp @@ -7,6 +7,7 @@ #include #include +#include namespace llmr { @@ -73,7 +74,7 @@ public: std::string name; std::shared_ptr source; std::string source_layer; - PropertyFilterExpression filter = std::true_type(); + FilterExpression filter; StyleBucketRender render = std::false_type(); }; diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index cdfd61094..29a41fb14 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -39,7 +39,6 @@ private: 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. @@ -54,9 +53,11 @@ private: template bool parseStyleProperty(const char *property_name, const std::vector &keys, ClassProperties &klass, JSVal value); -// PropertyFilterExpression parseFilterOrExpression(JSVal value); -// Value parseValue(JSVal value); -// + + FilterExpression parseFilter(JSVal, FilterExpression::Operator op); + FilterExpression parseFilter(JSVal); + Value parseValue(JSVal value); + std::forward_list parseValues(JSVal values); private: std::unordered_map constants; diff --git a/include/llmr/style/value.hpp b/include/llmr/style/value.hpp index 873438625..bdcba4cad 100644 --- a/include/llmr/style/value.hpp +++ b/include/llmr/style/value.hpp @@ -62,6 +62,8 @@ template <> struct string_to_number { template struct relaxed_operator_visitor { + typedef bool result_type; + bool operator()(bool lhs, bool rhs) const { return Operator()(lhs, rhs); } template ::value>::type> @@ -114,23 +116,23 @@ struct relaxed_less_equal_operator { } // end namespace detail inline bool relaxed_equal(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor()); + return apply_visitor(detail::relaxed_operator_visitor(), lhs, rhs); } inline bool relaxed_greater(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor()); + return apply_visitor(detail::relaxed_operator_visitor(), lhs, rhs); } inline bool relaxed_greater_equal(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor()); + return apply_visitor(detail::relaxed_operator_visitor(), lhs, rhs); } inline bool relaxed_less(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor()); + return apply_visitor(detail::relaxed_operator_visitor(), lhs, rhs); } inline bool relaxed_less_equal(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor()); + return apply_visitor(detail::relaxed_operator_visitor(), lhs, rhs); } } diff --git a/include/llmr/util/recursive_wrapper.hpp b/include/llmr/util/recursive_wrapper.hpp index 557b576c0..b87dc5699 100644 --- a/include/llmr/util/recursive_wrapper.hpp +++ b/include/llmr/util/recursive_wrapper.hpp @@ -1,19 +1,15 @@ -#ifndef LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP -#define LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP +#ifndef MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP +#define MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP #include -namespace llmr { - -namespace util { +namespace llmr { namespace util { template class recursive_wrapper { public: - - typedef T type; - + using type = T; private: T* p_; @@ -34,19 +30,19 @@ private: public: - recursive_wrapper& operator=(const recursive_wrapper& rhs) + inline recursive_wrapper& operator=(recursive_wrapper const& rhs) { assign( rhs.get() ); return *this; } - recursive_wrapper& operator=(const T& rhs) + inline recursive_wrapper& operator=(T const& rhs) { assign( rhs ); return *this; } - void swap(recursive_wrapper& operand) noexcept + inline void swap(recursive_wrapper& operand) noexcept { T* temp = operand.p_; operand.p_ = p_; @@ -71,10 +67,10 @@ public: T& get() { return *get_pointer(); } const T& get() const { return *get_pointer(); } - T* get_pointer() { return p_; } const T* get_pointer() const { return p_; } - + operator T const&() const { return this->get(); } + operator T&() { return this->get(); } }; template @@ -103,8 +99,9 @@ recursive_wrapper::recursive_wrapper(T const& operand) template recursive_wrapper::recursive_wrapper(recursive_wrapper&& operand) - : p_(new T( std::move(operand.get()) )) + : p_(operand.p_) { + operand.p_ = nullptr; } template @@ -125,8 +122,6 @@ inline void swap(recursive_wrapper& lhs, recursive_wrapper& rhs) noexcept lhs.swap(rhs); } -} +}} -} - -#endif // LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP +#endif // MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP diff --git a/include/llmr/util/variant.hpp b/include/llmr/util/variant.hpp index b887ae494..57f859343 100644 --- a/include/llmr/util/variant.hpp +++ b/include/llmr/util/variant.hpp @@ -1,5 +1,5 @@ -#ifndef UTIL_VARIANT_HPP -#define UTIL_VARIANT_HPP +#ifndef MAPBOX_UTIL_VARIANT_HPP +#define MAPBOX_UTIL_VARIANT_HPP #include #include @@ -9,50 +9,119 @@ #include // operator new #include // size_t #include +#include -#ifdef NDEBUG -#define VARIANT_INLINE inline __attribute__((always_inline)) +#include "recursive_wrapper.hpp" + +#ifdef _MSC_VER + // http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx + #ifdef NDEBUG + #define VARIANT_INLINE __forceinline + #else + #define VARIANT_INLINE __declspec(noinline) + #endif #else -#define VARIANT_INLINE __attribute__((noinline)) + #ifdef NDEBUG + #define VARIANT_INLINE inline __attribute__((always_inline)) + #else + #define VARIANT_INLINE __attribute__((noinline)) + #endif #endif -namespace llmr { +#define VARIANT_MAJOR_VERSION 0 +#define VARIANT_MINOR_VERSION 1 +#define VARIANT_PATCH_VERSION 0 -namespace util { +// translates to 100 +#define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION) -namespace detail { +namespace llmr { namespace util { namespace detail { static constexpr std::size_t invalid_value = std::size_t(-1); template -struct type_traits; +struct direct_type; template -struct type_traits +struct direct_type { - static constexpr std::size_t id = std::is_same::value ? sizeof...(Types) : type_traits::id; + static constexpr std::size_t index = std::is_same::value + ? sizeof...(Types) : direct_type::index; }; template -struct type_traits +struct direct_type { - static constexpr std::size_t id = invalid_value; + static constexpr std::size_t index = invalid_value; +}; + +template +struct convertible_type; + +template +struct convertible_type +{ + static constexpr std::size_t index = std::is_convertible::value + ? sizeof...(Types) : convertible_type::index; +}; + +template +struct convertible_type +{ + static constexpr std::size_t index = invalid_value; +}; + +template +struct value_traits +{ + static constexpr std::size_t direct_index = direct_type::index; + static constexpr std::size_t index = + (direct_index == invalid_value) ? convertible_type::index : direct_index; }; template struct is_valid_type; template -struct is_valid_type +struct is_valid_type { - static constexpr bool value = std::is_same::value - || is_valid_type::value; + static constexpr bool value = std::is_convertible::value + || is_valid_type::value; }; template struct is_valid_type : std::false_type {}; -} +template +struct select_type +{ + static_assert(N < sizeof...(Types), "index out of bounds"); +}; + +template +struct select_type +{ + using type = typename select_type::type; +}; + +template +struct select_type<0, T, Types...> +{ + using type = T; +}; + +} // namespace detail + +// static visitor +template +struct static_visitor +{ + using result_type = R; +protected: + static_visitor() {} + ~static_visitor() {} +}; + template struct static_max; @@ -125,37 +194,77 @@ template<> struct variant_helper<> namespace detail { +template +struct unwrapper +{ + T const& operator() (T const& obj) const + { + return obj; + } + + T& operator() (T & obj) const + { + return obj; + } +}; + + +template +struct unwrapper> +{ + auto operator() (recursive_wrapper const& obj) const + -> typename recursive_wrapper::type const& + { + return obj.get(); + } +}; + + template struct dispatcher; template -struct dispatcher +struct dispatcher { - typedef typename std::result_of::type result_type; - - VARIANT_INLINE static result_type apply(V const& v, F f) + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& v, F f) { - if (v.get_type_id() == sizeof...(Types)) + if (v.get_type_index() == sizeof...(Types)) { - return f(v. template get()); + return f(unwrapper()(v. template get())); } else { - return dispatcher::apply(v, f); + return dispatcher::apply_const(v, f); + } + } + + VARIANT_INLINE static result_type apply(V & v, F f) + { + if (v.get_type_index() == sizeof...(Types)) + { + return f(unwrapper()(v. template get())); + } + else + { + return dispatcher::apply(v, f); } } }; -template -struct dispatcher +template +struct dispatcher { - typedef typename std::result_of::type result_type; - - VARIANT_INLINE static result_type apply(V const&, F) + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, F) { - throw std::runtime_error("unary dispatch: FAIL"); + throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); } + VARIANT_INLINE static result_type apply(V &, F) + { + throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); + } }; @@ -163,28 +272,46 @@ template struct binary_dispatcher_rhs; template -struct binary_dispatcher_rhs +struct binary_dispatcher_rhs { - typedef typename std::result_of::type result_type; - VARIANT_INLINE static result_type apply(V const& lhs, V const& rhs, F f) + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) { - if (rhs.get_type_id() == sizeof...(Types)) // call binary functor + if (rhs.get_type_index() == sizeof...(Types)) // call binary functor { - return f(lhs. template get(), rhs. template get()); + return f(unwrapper()(lhs. template get()), + unwrapper()(rhs. template get())); } else { - return binary_dispatcher_rhs::apply(lhs, rhs, f); + return binary_dispatcher_rhs::apply_const(lhs, rhs, f); } } + + VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f) + { + if (rhs.get_type_index() == sizeof...(Types)) // call binary functor + { + return f(unwrapper()(lhs. template get()), + unwrapper()(rhs. template get())); + } + else + { + return binary_dispatcher_rhs::apply(lhs, rhs, f); + } + } + }; -template -struct binary_dispatcher_rhs +template +struct binary_dispatcher_rhs { - typedef typename std::result_of::type result_type; - - VARIANT_INLINE static result_type apply(V const&, V const&, F) + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } + VARIANT_INLINE static result_type apply(V &, V &, F) { throw std::runtime_error("binary dispatch: FAIL"); } @@ -195,28 +322,45 @@ template struct binary_dispatcher_lhs; template -struct binary_dispatcher_lhs +struct binary_dispatcher_lhs { - typedef typename std::result_of::type binary_result_type; - VARIANT_INLINE static binary_result_type apply(V const& lhs, V const& rhs, F f) + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) { - if (lhs.get_type_id() == sizeof...(Types)) // call binary functor + if (lhs.get_type_index() == sizeof...(Types)) // call binary functor { return f(lhs. template get(), rhs. template get()); } else { - return binary_dispatcher_lhs::apply(lhs, rhs, f); + return binary_dispatcher_lhs::apply_const(lhs, rhs, f); } } + + VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f) + { + if (lhs.get_type_index() == sizeof...(Types)) // call binary functor + { + return f(lhs. template get(), rhs. template get()); + } + else + { + return binary_dispatcher_lhs::apply(lhs, rhs, f); + } + } + }; -template -struct binary_dispatcher_lhs +template +struct binary_dispatcher_lhs { - typedef typename std::result_of::type result_type; + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } - VARIANT_INLINE static result_type apply(V const&, V const&, F) + VARIANT_INLINE static result_type apply(V &, V &, F) { throw std::runtime_error("binary dispatch: FAIL"); } @@ -226,37 +370,60 @@ template struct binary_dispatcher; template -struct binary_dispatcher +struct binary_dispatcher { - typedef typename std::result_of::type binary_result_type; - - VARIANT_INLINE static binary_result_type apply(V const& v0, V const& v1, F f) + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f) { - if (v0.get_type_id() == sizeof...(Types)) + if (v0.get_type_index() == sizeof...(Types)) { - if (v0.get_type_id() == v1.get_type_id()) + if (v0.get_type_index() == v1.get_type_index()) { return f(v0. template get(), v1. template get()); // call binary functor } else { - return binary_dispatcher_rhs::apply(v0, v1, f); + return binary_dispatcher_rhs::apply_const(v0, v1, f); } } - else if (v1.get_type_id() == sizeof...(Types)) + else if (v1.get_type_index() == sizeof...(Types)) { - return binary_dispatcher_lhs::apply(v0, v1, f); + return binary_dispatcher_lhs::apply_const(v0, v1, f); } - return binary_dispatcher::apply(v0, v1, f); + return binary_dispatcher::apply_const(v0, v1, f); + } + + VARIANT_INLINE static result_type apply(V & v0, V & v1, F f) + { + if (v0.get_type_index() == sizeof...(Types)) + { + if (v0.get_type_index() == v1.get_type_index()) + { + return f(v0. template get(), v1. template get()); // call binary functor + } + else + { + return binary_dispatcher_rhs::apply(v0, v1, f); + } + } + else if (v1.get_type_index() == sizeof...(Types)) + { + return binary_dispatcher_lhs::apply(v0, v1, f); + } + return binary_dispatcher::apply(v0, v1, f); } }; -template -struct binary_dispatcher +template +struct binary_dispatcher { - typedef typename std::result_of::type binary_result_type; + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } - VARIANT_INLINE static binary_result_type apply(V const&, V const&, F) + VARIANT_INLINE static result_type apply(V &, V &, F) { throw std::runtime_error("binary dispatch: FAIL"); } @@ -275,19 +442,19 @@ struct equal_comp struct less_comp { template - bool operator()(const T& lhs, const T& rhs) const + bool operator()(T const& lhs, T const& rhs) const { return lhs < rhs; } }; template -class comparer +class comparer : public static_visitor { public: explicit comparer(Variant const& lhs) noexcept : lhs_(lhs) {} - comparer& operator=(const comparer&) = delete; + comparer& operator=(comparer const&) = delete; // visitor template bool operator()(T const& rhs_content) const @@ -301,16 +468,16 @@ private: // operator<< helper template -class printer +class printer : public static_visitor<> { public: explicit printer(Out & out) : out_(out) {} - printer& operator=(printer const &) = delete; + printer& operator=(printer const&) = delete; // visitor template - void operator()( T const & operand) const + void operator()(T const& operand) const { out_ << operand; } @@ -318,7 +485,7 @@ private: Out & out_; }; -} // detail +} // namespace detail template class variant @@ -329,81 +496,106 @@ private: static const std::size_t data_align = static_max::value; using data_type = typename std::aligned_storage::type; - using helper_type = variant_helper; - std::size_t type_id; + std::size_t type_index; data_type data; public: VARIANT_INLINE variant() - : type_id(detail::invalid_value) {} - - template - VARIANT_INLINE explicit variant(T const& val) noexcept - : type_id(detail::type_traits::id) + : type_index(sizeof...(Types) - 1) { - static_assert(detail::is_valid_type::value, "Not a valid type for this variant"); - new (&data) T(val); + new (&data) typename detail::select_type<0, Types...>::type(); } - template - VARIANT_INLINE variant(T && val) noexcept - : type_id(detail::type_traits::id) + template ::value>::type> + VARIANT_INLINE explicit variant(T const& val) noexcept + : type_index(detail::value_traits::index) { - static_assert(detail::is_valid_type::value, "Not a valid type for this variant"); - new (&data) T(std::forward(val)); // nothrow + constexpr std::size_t index = sizeof...(Types) - detail::value_traits::index - 1; + using target_type = typename detail::select_type::type; + new (&data) target_type(val); + } + + template ::value>::type> + VARIANT_INLINE variant(T && val) noexcept + : type_index(detail::value_traits::index) + { + constexpr std::size_t index = sizeof...(Types) - detail::value_traits::index - 1; + using target_type = typename detail::select_type::type; + new (&data) target_type(std::forward(val)); // nothrow } VARIANT_INLINE variant(variant const& old) - : type_id(old.type_id) + : type_index(old.type_index) { - helper_type::copy(old.type_id, &old.data, &data); + helper_type::copy(old.type_index, &old.data, &data); } VARIANT_INLINE variant(variant&& old) noexcept - : type_id(old.type_id) + : type_index(old.type_index) { - helper_type::move(old.type_id, &old.data, &data); + helper_type::move(old.type_index, &old.data, &data); } friend void swap(variant & first, variant & second) { using std::swap; //enable ADL - swap(first.type_id, second.type_id); + swap(first.type_index, second.type_index); swap(first.data, second.data); } - VARIANT_INLINE variant& operator= (variant other) + VARIANT_INLINE variant& operator=(variant other) { swap(*this, other); return *this; } + // conversions + // move-assign + template + VARIANT_INLINE variant& operator=(T && rhs) noexcept + { + variant temp(std::move(rhs)); + swap(*this, temp); + return *this; + } + + // copy-assign + template + VARIANT_INLINE variant& operator=(T const& rhs) + { + variant temp(rhs); + swap(*this, temp); + return *this; + } + template VARIANT_INLINE bool is() const { - return (type_id == detail::type_traits::id); + return (type_index == detail::direct_type::index); } VARIANT_INLINE bool valid() const { - return (type_id != detail::invalid_value); + return (type_index != detail::invalid_value); } template VARIANT_INLINE void set(Args&&... args) { - helper_type::destroy(type_id, &data); + helper_type::destroy(type_index, &data); new (&data) T(std::forward(args)...); - type_id = detail::type_traits::id; + type_index = detail::direct_type::index; } template VARIANT_INLINE T& get() { - if (type_id == detail::type_traits::id) + if (type_index == detail::direct_type::index) { return *reinterpret_cast(&data); } @@ -416,7 +608,7 @@ public: template VARIANT_INLINE T const& get() const { - if (type_id == detail::type_traits::id) + if (type_index == detail::direct_type::index) { return *reinterpret_cast(&data); } @@ -426,37 +618,57 @@ public: } } - VARIANT_INLINE std::size_t get_type_id() const + VARIANT_INLINE std::size_t get_type_index() const { - return type_id; + return type_index; } // visitor // unary template - typename std::result_of::type - VARIANT_INLINE static visit(V const& v, F f) + auto VARIANT_INLINE + static visit(V const& v, F f) + -> decltype(detail::dispatcher::apply_const(v, f)) + { + return detail::dispatcher::apply_const(v, f); + } + // non-const + template + auto VARIANT_INLINE + static visit(V & v, F f) + -> decltype(detail::dispatcher::apply(v, f)) { return detail::dispatcher::apply(v, f); } + // binary + // const template - typename std::result_of::type - VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F f) + auto VARIANT_INLINE + static binary_visit(V const& v0, V const& v1, F f) + -> decltype(detail::binary_dispatcher::apply_const(v0, v1, f)) + { + return detail::binary_dispatcher::apply_const(v0, v1, f); + } + // non-const + template + auto VARIANT_INLINE + static binary_visit(V& v0, V& v1, F f) + -> decltype(detail::binary_dispatcher::apply(v0, v1, f)) { return detail::binary_dispatcher::apply(v0, v1, f); } ~variant() noexcept { - helper_type::destroy(type_id, &data); + helper_type::destroy(type_index, &data); } // comparison operators // equality VARIANT_INLINE bool operator==(variant const& rhs) const { - if (this->get_type_id() != rhs.get_type_id()) + if (this->get_type_index() != rhs.get_type_index()) return false; detail::comparer visitor(*this); return visit(rhs, visitor); @@ -464,9 +676,9 @@ public: // less than VARIANT_INLINE bool operator<(variant const& rhs) const { - if (this->get_type_id() != rhs.get_type_id()) + if (this->get_type_index() != rhs.get_type_index()) { - return this->get_type_id() < rhs.get_type_id(); + return this->get_type_index() < rhs.get_type_index(); // ^^ borrowed from boost::variant } detail::comparer visitor(*this); @@ -475,17 +687,30 @@ public: }; // unary visitor interface + +// const template -typename std::result_of::type -VARIANT_INLINE static apply_visitor(V const& v, F f) +auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f)) { - return V::visit(v,f); + return V::visit(v, f); +} +// non-const +template +auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f)) +{ + return V::visit(v, f); } // binary visitor interface +// const template -typename std::result_of::type -VARIANT_INLINE static apply_visitor(V const& v0, V const& v1, F f) +auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f)) +{ + return V::binary_visit(v0, v1, f); +} +// non-const +template +auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f)) { return V::binary_visit(v0, v1, f); } @@ -493,14 +718,14 @@ VARIANT_INLINE static apply_visitor(V const& v0, V const& v1, F f) // operator<< template -VARIANT_INLINE std::basic_ostream& -operator<< (std::basic_ostream& out, Variant const& rhs) +VARIANT_INLINE std::basic_ostream& +operator<< (std::basic_ostream& out, Variant const& rhs) { - detail::printer > visitor(out); - apply_visitor(rhs, visitor); + detail::printer> visitor(out); + apply_visitor(visitor, rhs); return out; } -} -} -#endif // UTIL_VARIANT_HPP +}} + +#endif // MAPBOX_UTIL_VARIANT_HPP diff --git a/src/map/filter_expression.cpp b/src/map/filter_expression.cpp new file mode 100644 index 000000000..9e293b002 --- /dev/null +++ b/src/map/filter_expression.cpp @@ -0,0 +1,282 @@ +#include +#include + +namespace llmr { + + +template +inline bool FilterComparison::Instance::includes(const Value &property_value, const Comparer &comparer) const { + for (const Value &filter_value : values) { + if (comparer(property_value, filter_value)) { + return true; + } + } + return false; +} + +template +inline bool FilterComparison::Instance::compare(const Value &property_value, const Comparer &comparer) const { + for (const Value &filter_value : values) { + if (!comparer(property_value, filter_value)) { + return false; + } + } + return true; +} + +template +inline bool FilterComparison::Instance::all(const std::forward_list &property_values, const Comparer &comparer) const { + for (const Value &property_value : property_values) { + if (!compare(property_value, comparer)) { + return false; + } + } + return true; +} + + + +bool FilterComparison::Instance::compare(const Value &property_value) const { + switch (op) { + case Operator::Equal: + case Operator::In: + return includes(property_value, util::relaxed_equal); + case Operator::NotEqual: + case Operator::NotIn: + return !includes(property_value, util::relaxed_equal); + case Operator::Greater: + return compare(property_value, util::relaxed_greater); + case Operator::GreaterEqual: + return compare(property_value, util::relaxed_greater_equal); + case Operator::Less: + return compare(property_value, util::relaxed_less); + case Operator::LessEqual: + return compare(property_value, util::relaxed_less_equal); + default: + return false; + } +} + +bool FilterComparison::Instance::compare(const std::forward_list &property_values) const { + switch (op) { + case Operator::Equal: + for (const Value &property_value : property_values) { + if (!includes(property_value, util::relaxed_equal)) { + return false; + } + } + return true; + case Operator::NotEqual: + for (const Value &property_value : property_values) { + if (includes(property_value, util::relaxed_equal)) { + return false; + } + } + return true; + case Operator::In: + for (const Value &property_value : property_values) { + if (includes(property_value, util::relaxed_equal)) { + return true; + } + } + return false; + case Operator::NotIn: + for (const Value &property_value : property_values) { + if (!includes(property_value, util::relaxed_equal)) { + return true; + } + } + return false; + case Operator::Greater: + return all(property_values, util::relaxed_greater); + case Operator::GreaterEqual: + return all(property_values, util::relaxed_greater_equal); + case Operator::Less: + return all(property_values, util::relaxed_less); + case Operator::LessEqual: + return all(property_values, util::relaxed_less_equal); + } +} + + +const std::string &FilterComparison::getField() const { + return field; +} + +inline bool FilterComparison::compare(const VectorTileTagExtractor &extractor) const { + const std::forward_list values = extractor.getValues(field); + + // All instances are ANDed together. + for (const Instance &instance : instances) { + if (!instance.compare(values)) { + return false; + } + } + return true; +} + + + +std::ostream& operator <<(std::ostream &s, const FilterComparison &comparison) { + s << "comparison" << std::endl; + for (const FilterComparison::Instance &instance : comparison.instances) { + s << " - " << comparison.field << " " << instance << std::endl; + } + return s; +} + + +std::ostream& operator <<(std::ostream &s, const FilterComparison::Instance &instance) { + switch (instance.op) { + case FilterComparison::Operator::Equal: s << "=="; break; + case FilterComparison::Operator::NotEqual: s << "!="; break; + case FilterComparison::Operator::Greater: s << ">"; break; + case FilterComparison::Operator::GreaterEqual: s << ">="; break; + case FilterComparison::Operator::Less: s << "<"; break; + case FilterComparison::Operator::LessEqual: s << "<="; break; + case FilterComparison::Operator::In: s << "in"; break; + case FilterComparison::Operator::NotIn: s << "!in"; break; + } + + s << " [ "; + for (const Value &value : instance.values) { + s << toString(value) << " "; + } + s << "]"; + return s; +} + + +FilterComparison::Operator parseFilterComparisonOperator(const std::string &op) { + if (op == "==") return FilterComparison::Operator::Equal; + if (op == "!=") return FilterComparison::Operator::NotEqual; + if (op == ">") return FilterComparison::Operator::Greater; + if (op == ">=") return FilterComparison::Operator::GreaterEqual; + if (op == "<") return FilterComparison::Operator::Less; + if (op == "<=") return FilterComparison::Operator::LessEqual; + if (op == "in") return FilterComparison::Operator::In; + if (op == "!in") return FilterComparison::Operator::NotIn; + return FilterComparison::Operator::Equal; +} + + +std::ostream& operator <<(std::ostream &s, FilterExpression::Operator op) { + switch (op) { + case FilterExpression::Operator::And: s << "AND"; break; + case FilterExpression::Operator::Or: s << "OR"; break; + case FilterExpression::Operator::Xor: s << "XOR"; break; + case FilterExpression::Operator::Nor: s << "NOR"; break; + } + return s; +} + + +std::ostream& operator <<(std::ostream &s, FilterExpression::GeometryType type) { + switch (type) { + case FilterExpression::GeometryType::Point: s << "point"; break; + case FilterExpression::GeometryType::Line: s << "line"; break; + case FilterExpression::GeometryType::Polygon: s << "polygon"; break; + case FilterExpression::GeometryType::Any: s << "any"; break; + } + return s; +} + + + +bool FilterExpression::compare(const VectorTileTagExtractor &extractor) const { + if (type != GeometryType::Any && extractor.getType() != type && extractor.getType() != GeometryType::Any) { + return false; + } + + switch (op) { + case Operator::And: + for (const FilterComparison &comparison : comparisons) { + if (!comparison.compare(extractor)) { + return false; + } + } + for (const FilterExpression &expression: expressions) { + if (!expression.compare(extractor)) { + return false; + } + } + return true; + case Operator::Or: + for (const FilterComparison &comparison : comparisons) { + if (comparison.compare(extractor)) { + return true; + } + } + for (const FilterExpression &expression: expressions) { + if (expression.compare(extractor)) { + return true; + } + } + return false; + case Operator::Xor: { + int count = 0; + for (const FilterComparison &comparison : comparisons) { + count += comparison.compare(extractor); + if (count > 1) { + return false; + } + } + for (const FilterExpression &expression: expressions) { + count += expression.compare(extractor); + if (count > 1) { + return false; + } + } + return count == 1; + } + case Operator::Nor: + for (const FilterComparison &comparison : comparisons) { + if (comparison.compare(extractor)) { + return false; + } + } + for (const FilterExpression &expression: expressions) { + if (expression.compare(extractor)) { + return false; + } + } + return true; + default: + return true; + } +} + +bool FilterExpression::empty() const { + return type == GeometryType::Any && comparisons.empty() && expressions.empty(); +} + +void FilterExpression::add(const FilterComparison &comparison) { + comparisons.emplace_front(comparison); +} + +void FilterExpression::add(const FilterExpression &expression) { + expressions.emplace_front(expression); +} + +void FilterExpression::setGeometryType(GeometryType g) { + type = g; +} + +FilterExpression::GeometryType parseGeometryType(const std::string &geometry) { + if (geometry == "point") return FilterExpression::GeometryType::Point; + if (geometry == "line") return FilterExpression::GeometryType::Line; + if (geometry == "polygon") return FilterExpression::GeometryType::Polygon; + return FilterExpression::GeometryType::Any; +} + +std::ostream& operator <<(std::ostream &s, const FilterExpression &expression) { + s << "expression " << expression.op << std::endl; + s << " - $type = " << expression.type << std::endl; + for (const FilterComparison &comparison : expression.comparisons) { + s << comparison; + } + s << "end expression" << std::endl; + return s; +} + +} diff --git a/src/map/map.cpp b/src/map/map.cpp index 01f7ac607..db94ca97d 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -169,8 +169,6 @@ void Map::setup() { view.make_active(); painter.setup(); - - setStyleJSON(styleJSON); } void Map::setStyleJSON(std::string newStyleJSON) { diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index b4041ada4..e834e6fa9 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -132,7 +132,7 @@ std::unique_ptr TileParser::createBucket(std::shared_ptr bu } template -void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter) { +void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter) { FilteredVectorTileLayer filtered_layer(layer, filter); for (pbf feature : filtered_layer) { if (obsolete()) @@ -150,7 +150,7 @@ void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, } template -void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter, Args&& ...args) { +void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter, Args&& ...args) { FilteredVectorTileLayer filtered_layer(layer, filter); for (const pbf &feature_pbf : filtered_layer) { if (obsolete()) { @@ -161,25 +161,25 @@ void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, } -std::unique_ptr TileParser::createFillBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketFill &fill) { +std::unique_ptr TileParser::createFillBucket(const VectorTileLayer& layer, const FilterExpression &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 PropertyFilterExpression &filter, const StyleBucketLine &line) { +std::unique_ptr TileParser::createLineBucket(const VectorTileLayer& layer, const FilterExpression &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 PropertyFilterExpression &filter, const StyleBucketIcon &icon) { +std::unique_ptr TileParser::createIconBucket(const VectorTileLayer& layer, const FilterExpression &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); } -std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketText &text) { +std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketText &text) { const StyleBucketText &properties = text; @@ -235,9 +235,3 @@ 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 24f03e1a9..54a971cd8 100644 --- a/src/map/vector_tile.cpp +++ b/src/map/vector_tile.cpp @@ -102,7 +102,7 @@ VectorTileLayer::VectorTileLayer(pbf layer) : data(layer) { } } -FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const PropertyFilterExpression &filterExpression) +FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const FilterExpression &filterExpression) : layer(layer), filterExpression(filterExpression) { } @@ -122,120 +122,167 @@ FilteredVectorTileLayer::iterator::iterator(const FilteredVectorTileLayer& paren operator++(); } -bool FilteredVectorTileLayer::iterator::matchesFilterExpression(const PropertyFilterExpression &filterExpression, const pbf &tags_pbf) { - if (filterExpression.is>()) { - return matchesFilter(filterExpression.get>().get(), tags_pbf); - } else if (filterExpression.is>()) { - return matchesExpression(filterExpression.get>().get(), tags_pbf); - } else if (filterExpression.is()) { - return true; - } else { - return false; - } +//bool FilteredVectorTileLayer::iterator::matchesFilterExpression(const FilterExpression &filterExpression, const pbf &tags_pbf) { +// if (filterExpression.empty()) { +// return true; +// } +// +// +// +// +// if (filterExpression.is>()) { +// return matchesFilter(filterExpression.get>().get(), tags_pbf); +// } else if (filterExpression.is>()) { +// return matchesExpression(filterExpression.get>().get(), tags_pbf); +// } else if (filterExpression.is()) { +// return true; +// } else { +// return false; +// } +// return true; +//} + +// +//bool FilteredVectorTileLayer::iterator::matchesFilter(const PropertyFilter &filter, const pbf &const_tags_pbf) { +// auto field_it = parent.layer.key_index.find(filter.field); +// if (field_it != parent.layer.key_index.end()) { +// const uint32_t filter_key = field_it->second; +// +// // Now loop through all the key/value pair tags. +// // tags are packed varints. They should have an even length. +// pbf tags_pbf = const_tags_pbf; +// while (tags_pbf) { +// uint32_t tag_key = tags_pbf.varint(); +// if (!tags_pbf) { +// // This should not happen; otherwise the vector tile +// // is invalid. +// throw std::runtime_error("uneven number of feature tag ids"); +// } +// uint32_t tag_val = tags_pbf.varint(); +// +// if (tag_key == filter_key) { +// if (parent.layer.values.size() > tag_val) { +// const Value &value = parent.layer.values[tag_val]; +// return filter.compare(value); +// } else { +// throw std::runtime_error("feature references out of range value"); +// } +// } +// } +// } +// +// // The feature doesn't contain the field that we're looking to compare. +// // Depending on the filter, this may still be okay. +// return filter.isMissingFieldOkay(); +//} +// +//bool FilteredVectorTileLayer::iterator::matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf) { +// if (expression.op == ExpressionOperator::Or) { +// for (const PropertyFilterExpression &filterExpression : expression.operands) { +// if (matchesFilterExpression(filterExpression, tags_pbf)) { +// return true; +// } +// } +// return false; +// } else if (expression.op == ExpressionOperator::And) { +// for (const PropertyFilterExpression &filterExpression : expression.operands) { +// if (!matchesFilterExpression(filterExpression, tags_pbf)) { +// return false; +// } +// } +// return true; +// } else { +// return false; +// } +//} +// + +VectorTileTagExtractor::VectorTileTagExtractor(const VectorTileLayer &layer) : layer_(layer) {} + + +void VectorTileTagExtractor::setTags(const pbf &pbf) { + tags_ = pbf; } +std::forward_list VectorTileTagExtractor::getValues(const std::string &key) const { + std::forward_list values; -bool FilteredVectorTileLayer::iterator::matchesFilter(const PropertyFilter &filter, const pbf &const_tags_pbf) { - auto field_it = parent.layer.key_index.find(filter.field); - if (field_it != parent.layer.key_index.end()) { + auto field_it = layer_.key_index.find(key); + if (field_it != layer_.key_index.end()) { + auto it = values.before_begin(); const uint32_t filter_key = field_it->second; // Now loop through all the key/value pair tags. // tags are packed varints. They should have an even length. - pbf tags_pbf = const_tags_pbf; + pbf tags_pbf = tags_; + uint32_t tag_key, tag_val; while (tags_pbf) { - uint32_t tag_key = tags_pbf.varint(); + tag_key = tags_pbf.varint(); if (!tags_pbf) { - // This should not happen; otherwise the vector tile - // is invalid. - throw std::runtime_error("uneven number of feature tag ids"); + // This should not happen; otherwise the vector tile is invalid. + fprintf(stderr, "[WARNING] uneven number of feature tag ids\n"); + return values; } - uint32_t tag_val = tags_pbf.varint(); + // Note: We need to run this command in all cases, even if the keys don't match. + tag_val = tags_pbf.varint(); if (tag_key == filter_key) { - if (parent.layer.values.size() > tag_val) { - const Value &value = parent.layer.values[tag_val]; - return filter.compare(value); + if (layer_.values.size() > tag_val) { + it = values.emplace_after(it, layer_.values[tag_val]); } else { - throw std::runtime_error("feature references out of range value"); + fprintf(stderr, "[WARNING] feature references out of range value\n"); + break; } } } } - // The feature doesn't contain the field that we're looking to compare. - // Depending on the filter, this may still be okay. - return filter.isMissingFieldOkay(); + return values; } -bool FilteredVectorTileLayer::iterator::matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf) { - if (expression.op == ExpressionOperator::Or) { - for (const PropertyFilterExpression &filterExpression : expression.operands) { - if (matchesFilterExpression(filterExpression, tags_pbf)) { - return true; - } - } - return false; - } else if (expression.op == ExpressionOperator::And) { - for (const PropertyFilterExpression &filterExpression : expression.operands) { - if (!matchesFilterExpression(filterExpression, tags_pbf)) { - return false; - } - } - return true; - } else { - return false; - } +void VectorTileTagExtractor::setType(FilterExpression::GeometryType type) { + type_ = type; } - +FilterExpression::GeometryType VectorTileTagExtractor::getType() const { + return type_; +} void FilteredVectorTileLayer::iterator::operator++() { valid = false; - const PropertyFilterExpression &expression = parent.filterExpression; + const FilterExpression &expression = parent.filterExpression; while (data.next(2)) { // feature feature = data.message(); pbf feature_pbf = feature; - BucketType type = BucketType::None; - bool matched = false; // Treat the absence of any expression filters as a match. - if (!expression.valid() || expression.is()) { + if (expression.empty()) { matched = true; } - while (feature_pbf.next()) { - if (feature_pbf.tag == 2) { // tags - if (matched) { - // There is no filter, so we want to parse the entire layer anyway. - feature_pbf.skip(); - } else { - // We only want to parse some features. - const pbf tags_pbf = feature_pbf.message(); - matched = matchesFilterExpression(expression, tags_pbf); - if (!matched) { - break; // feature_pbf loop early - } - } - } else if (feature_pbf.tag == 3) { // geometry type - switch (feature_pbf.varint()) { - case 1 /* Point */: type = BucketType::Icon; break; - case 2 /* LineString */: type = BucketType::Line; break; - case 3 /* Polygon */: type = BucketType::Fill; break; - default: type = BucketType::None; break; - } + if (!matched) { + VectorTileTagExtractor extractor(parent.layer); - // TODO: Parse feature type -// if (type != parent.bucket_desc.feature_type) { -// matched = false; -// break; // feature_pbf loop early -// } - } else { - feature_pbf.skip(); + // Retrieve the basic information + while (feature_pbf.next()) { + if (feature_pbf.tag == 2) { // tags + extractor.setTags(feature_pbf.message()); + } else if (feature_pbf.tag == 3) { // geometry type + switch (FeatureType(feature_pbf.varint())) { + case FeatureType::Point: extractor.setType(FilterExpression::GeometryType::Point); break; + case FeatureType::LineString: extractor.setType(FilterExpression::GeometryType::Line); break; + case FeatureType::Polygon: extractor.setType(FilterExpression::GeometryType::Polygon); break; + default: break; + } + } else { + feature_pbf.skip(); + } } + + matched = expression.compare(extractor); } if (matched) { diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 390096e9d..34aa7f222 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -622,7 +622,7 @@ void StyleParser::parseBucket(JSVal value, std::shared_ptr &layer) { if (value.HasMember("filter")) { JSVal value_filter = replaceConstant(value["filter"]); - parseFilter(value_filter, layer); + layer->bucket->filter = parseFilter(value_filter); } if (value.HasMember("render")) { @@ -631,8 +631,92 @@ void StyleParser::parseBucket(JSVal value, std::shared_ptr &layer) { } } -void StyleParser::parseFilter(JSVal value, std::shared_ptr &layer) { - // TODO +FilterExpression StyleParser::parseFilter(JSVal value) { + return parseFilter(value, value.IsArray() ? FilterExpression::Operator::Or : FilterExpression::Operator::And); +} + +FilterExpression StyleParser::parseFilter(JSVal value, FilterExpression::Operator op) { + FilterExpression expression(op); + if (value.IsObject()) { + rapidjson::Value::ConstMemberIterator itr = value.MemberBegin(); + for (; itr != value.MemberEnd(); ++itr) { + const std::string name { itr->name.GetString(), itr->name.GetStringLength() }; + if (name == "&") { + expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::And)); + } else if (name == "|") { + expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::Or)); + } else if (name == "^") { + expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::Xor)); + } else if (name == "!") { + expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::Nor)); + } else if (name == "$type") { + JSVal type = replaceConstant(itr->value); + if (type.IsString()) { + expression.setGeometryType(parseGeometryType({ type.GetString(), type.GetStringLength() })); + } + } else { + FilterComparison comparison(name); + JSVal filterValue = replaceConstant(itr->value); + if (filterValue.IsObject()) { + rapidjson::Value::ConstMemberIterator itr = filterValue.MemberBegin(); + for (; itr != filterValue.MemberEnd(); ++itr) { + comparison.add( + parseFilterComparisonOperator({ itr->name.GetString(), itr->name.GetStringLength() }), + parseValues(replaceConstant(itr->value)) + ); + } + } else if (filterValue.IsArray()) { + comparison.add(FilterComparison::Operator::In, parseValues(filterValue)); + } else { + comparison.add(FilterComparison::Operator::Equal, std::forward_list({ parseValue(filterValue) })); + } + expression.add(comparison); + } + } + } else if (value.IsArray()) { + for (rapidjson::SizeType i = 0; i < value.Size(); i++) { + expression.add(parseFilter(replaceConstant(value[i]))); + } + } else { + fprintf(stderr, "[WARNING] expression must be either an array or an object\n"); + } + + return expression; +} + +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(); + + default: + return false; + } +} + +std::forward_list StyleParser::parseValues(JSVal value) { + std::forward_list values; + if (value.IsArray()) { + auto it = values.before_begin(); + for (rapidjson::SizeType i = 0; i < value.Size(); i++) { + it = values.emplace_after(it, parseValue(replaceConstant(value[i]))); + } + } else { + values.emplace_front(parseValue(value)); + } + return values; } void StyleParser::parseRender(JSVal value, std::shared_ptr &layer) { @@ -724,79 +808,4 @@ void StyleParser::parseRender(JSVal value, std::shared_ptr &layer) { } } -//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; -//} - } From 99d939b9a66f4d59d06b4d8a76a10f4b57324cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 26 Jun 2014 15:16:28 +0200 Subject: [PATCH 10/55] cleanup --- include/llmr/style/bucket_description.hpp | 17 - include/llmr/style/style.hpp | 72 +- src/style/bucket_description.cpp | 9 - src/style/style.cpp | 1019 +-------------------- 4 files changed, 3 insertions(+), 1114 deletions(-) diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index 6011b5399..de84fc1ce 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -12,23 +12,6 @@ namespace llmr { -// Deprecated -class BucketDescription { -public: - BucketType feature_type = BucketType::None; - BucketType type = BucketType::None; - - // Specify what data to pull into this bucket - std::string source_name; - std::string source_layer; - - FilterExpression filter; - - // Specifies how the geometry for this bucket should be created - StyleBucketRender render; -}; - -std::ostream& operator<<(std::ostream&, const BucketDescription& bucket); std::ostream& operator<<(std::ostream&, BucketType type); } diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index 1c4cf11d4..bc3605737 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -87,81 +87,13 @@ private: 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; - -// // 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; uint64_t default_transition_duration = 0; bool initial_render_complete = false; mutable uv::rwlock mtx; - }; } - - -#endif \ No newline at end of file +#endif +¯ \ No newline at end of file diff --git a/src/style/bucket_description.cpp b/src/style/bucket_description.cpp index 24d086f64..22e7898e0 100644 --- a/src/style/bucket_description.cpp +++ b/src/style/bucket_description.cpp @@ -2,15 +2,6 @@ #include - -std::ostream& llmr::operator<<(std::ostream& os, const BucketDescription& bucket) { - os << "Bucket:" << std::endl; - os << " - type: " << (uint32_t)bucket.type << std::endl; - os << " - source_name: " << bucket.source_name << std::endl; - os << " - source_layer: " << bucket.source_layer << std::endl; - return os; -} - std::ostream& llmr::operator<<(std::ostream& os, BucketType type) { switch (type) { case BucketType::None: os << "None"; return os; diff --git a/src/style/style.cpp b/src/style/style.cpp index 264cef0b6..87cfd81f8 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -13,16 +13,6 @@ Style::Style() { } 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(); } void Style::updateSources() { @@ -50,322 +40,6 @@ void Style::updateSources(const std::shared_ptr &layers) { } } -//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; -// } -//} - -//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(); @@ -510,721 +184,31 @@ void Style::cascade(float z) { 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); -// reset(); - - // TODO: Make this per-layer once individual layers have a specific tile size. -// 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; -// - // 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; -// - // 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; -// } -// } -// } - // Apply transitions after the first time. if (!initial_render_complete) { initial_render_complete = true; 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; -// } -//} -// + 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; -// } -// } - 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++; -// } -// } -// } } 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; -//} -// void Style::setDefaultTransitionDuration(uint64_t duration_milliseconds) { default_transition_duration = duration_milliseconds; } @@ -1244,7 +228,6 @@ void Style::toggleClass(const std::string &name) { } } - void Style::loadJSON(const uint8_t *const data) { uv::writelock lock(mtx); From 084c938e541fcc4edcf219bb9cdabc523f402db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 26 Jun 2014 15:32:18 +0200 Subject: [PATCH 11/55] fix fill outline color --- include/llmr/style/properties.hpp | 2 +- include/llmr/style/style.hpp | 1 - src/renderer/painter_fill.cpp | 12 ++++++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index 644fd34cc..8deff16c0 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -226,7 +226,7 @@ struct FillProperties { bool antialias = true; float opacity = 1.0f; Color fill_color = {{ 0, 0, 0, 1 }}; - Color stroke_color = {{ 0, 0, 0, 1 }}; + Color stroke_color = {{ 0, 0, 0, -1 }}; std::array translate = {{ 0, 0 }}; TranslateAnchorType translateAnchor = TranslateAnchorType::Default; std::string image; diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index bc3605737..b9f221b2d 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -96,4 +96,3 @@ private: } #endif -¯ \ No newline at end of file diff --git a/src/renderer/painter_fill.cpp b/src/renderer/painter_fill.cpp index 4628db7f7..fa79cb8de 100644 --- a/src/renderer/painter_fill.cpp +++ b/src/renderer/painter_fill.cpp @@ -17,10 +17,14 @@ void Painter::renderFill(FillBucket& bucket, const FillProperties& properties, c fill_color[3] *= properties.opacity; Color stroke_color = properties.stroke_color; - stroke_color[0] *= properties.opacity; - stroke_color[1] *= properties.opacity; - stroke_color[2] *= properties.opacity; - stroke_color[3] *= properties.opacity; + if (stroke_color[3] < 0) { + stroke_color = fill_color; + } else { + stroke_color[0] *= properties.opacity; + stroke_color[1] *= properties.opacity; + stroke_color[2] *= properties.opacity; + stroke_color[3] *= properties.opacity; + } bool outline = properties.antialias && properties.stroke_color != properties.fill_color; bool fringeline = properties.antialias && properties.stroke_color == properties.fill_color; From 6de9d9769e601284347b73231d286dc645ee1b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 26 Jun 2014 21:54:57 +0200 Subject: [PATCH 12/55] cleanup --- include/llmr/renderer/debug_bucket.hpp | 1 - include/llmr/renderer/fill_bucket.hpp | 2 +- include/llmr/renderer/icon_bucket.hpp | 2 +- include/llmr/renderer/line_bucket.hpp | 3 +- include/llmr/renderer/raster_bucket.hpp | 1 - include/llmr/renderer/text_bucket.hpp | 3 +- include/llmr/style/bucket_description.hpp | 19 ------ include/llmr/style/class_description.hpp | 39 ------------ include/llmr/style/layer_description.hpp | 22 ------- include/llmr/style/properties.hpp | 73 ----------------------- include/llmr/style/style.hpp | 4 +- include/llmr/style/types.hpp | 14 ++--- src/map/vector_tile.cpp | 1 - src/style/bucket_description.cpp | 15 ----- src/style/class_description.cpp | 9 --- src/style/layer_description.cpp | 22 ------- src/style/types.cpp | 31 ++++++++++ src/text/placement.cpp | 1 - 18 files changed, 43 insertions(+), 219 deletions(-) delete mode 100644 include/llmr/style/bucket_description.hpp delete mode 100644 include/llmr/style/class_description.hpp delete mode 100644 include/llmr/style/layer_description.hpp delete mode 100644 src/style/bucket_description.cpp delete mode 100644 src/style/class_description.cpp delete mode 100644 src/style/layer_description.cpp create mode 100644 src/style/types.cpp diff --git a/include/llmr/renderer/debug_bucket.hpp b/include/llmr/renderer/debug_bucket.hpp index b0b4f7cd0..d72a645ee 100644 --- a/include/llmr/renderer/debug_bucket.hpp +++ b/include/llmr/renderer/debug_bucket.hpp @@ -2,7 +2,6 @@ #define LLMR_RENDERER_DEBUGBUCKET #include -#include #include #include diff --git a/include/llmr/renderer/fill_bucket.hpp b/include/llmr/renderer/fill_bucket.hpp index 95de06464..db0e9c104 100644 --- a/include/llmr/renderer/fill_bucket.hpp +++ b/include/llmr/renderer/fill_bucket.hpp @@ -2,9 +2,9 @@ #define LLMR_RENDERER_FILLBUCKET #include -#include #include #include +#include #include #include diff --git a/include/llmr/renderer/icon_bucket.hpp b/include/llmr/renderer/icon_bucket.hpp index e6fe161f1..d13f53586 100644 --- a/include/llmr/renderer/icon_bucket.hpp +++ b/include/llmr/renderer/icon_bucket.hpp @@ -2,9 +2,9 @@ #define LLMR_RENDERER_ICONBUCKET #include -#include #include #include +#include #include #include diff --git a/include/llmr/renderer/line_bucket.hpp b/include/llmr/renderer/line_bucket.hpp index f33982a52..881bd23eb 100644 --- a/include/llmr/renderer/line_bucket.hpp +++ b/include/llmr/renderer/line_bucket.hpp @@ -2,10 +2,11 @@ #define LLMR_RENDERER_LINEBUCKET #include "bucket.hpp" -#include #include #include #include +#include + #include #include diff --git a/include/llmr/renderer/raster_bucket.hpp b/include/llmr/renderer/raster_bucket.hpp index bbd5dee27..86bb1d925 100644 --- a/include/llmr/renderer/raster_bucket.hpp +++ b/include/llmr/renderer/raster_bucket.hpp @@ -2,7 +2,6 @@ #define LLMR_RENDERER_RASTERBUCKET #include -#include #include namespace llmr { diff --git a/include/llmr/renderer/text_bucket.hpp b/include/llmr/renderer/text_bucket.hpp index abc95b165..4d9bf382d 100644 --- a/include/llmr/renderer/text_bucket.hpp +++ b/include/llmr/renderer/text_bucket.hpp @@ -2,12 +2,13 @@ #define LLMR_RENDERER_TEXTBUCKET #include "bucket.hpp" -#include #include #include #include #include #include +#include + #include #include #include diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp deleted file mode 100644 index de84fc1ce..000000000 --- a/include/llmr/style/bucket_description.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef LLMR_STYLE_BUCKET_DESCRIPTION -#define LLMR_STYLE_BUCKET_DESCRIPTION - -#include -#include -#include - -#include -#include -#include -#include - -namespace llmr { - -std::ostream& operator<<(std::ostream&, BucketType type); - -} - -#endif diff --git a/include/llmr/style/class_description.hpp b/include/llmr/style/class_description.hpp deleted file mode 100644 index 6bd2a03c1..000000000 --- a/include/llmr/style/class_description.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef LLMR_STYLE_CLASS_DESCRIPTION -#define LLMR_STYLE_CLASS_DESCRIPTION - -#include -#include -#include "properties.hpp" - -namespace llmr { - -class ClassDescription { -public: - inline const ClassProperties &operator[](const std::string &name) const { - auto it = styles.find(name); - if (it != styles.end()) { - return it->second; - } else { - return defaultProperties; - } - } - - void addClass(const std::string &name, ClassProperties &&properties); - - inline std::unordered_map::const_iterator begin() const { - return styles.begin(); - } - - inline std::unordered_map::const_iterator end() const { - return styles.end(); - } - -private: - std::unordered_map styles; - static const ClassProperties defaultProperties; -}; - - -} - -#endif diff --git a/include/llmr/style/layer_description.hpp b/include/llmr/style/layer_description.hpp deleted file mode 100644 index 75013db72..000000000 --- a/include/llmr/style/layer_description.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef LLMR_STYLE_LAYER_DESCRIPTION -#define LLMR_STYLE_LAYER_DESCRIPTION - -#include -#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); - -} - -#endif diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index 8deff16c0..32ef18760 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -25,22 +25,6 @@ struct ClassPropertyTransition { uint16_t delay = 0; }; -enum class TransitionablePropertyKey { - Translate = 1, - FillColor = 2, - StrokeColor = 3, - Opacity = 4, - Width = 5, - Offset = 6, - Color = 7, - DashArray = 8, - Radius = 9, - Blur = 10, - Halo = 11, - HaloRadius = 12, - HaloBlur = 13, -}; - enum class Property { Null = 1, Constant = 2, @@ -187,38 +171,6 @@ 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 FillProperties { FillProperties() {} @@ -325,18 +277,6 @@ typedef util::variant< 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; @@ -347,17 +287,4 @@ public: } - -namespace std { - -template <> struct hash { -public: - inline size_t operator()(llmr::TransitionablePropertyKey prop) const { - typedef typename std::underlying_type::type type; - return std::hash()(static_cast(prop)); - } -}; - -} - #endif diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index b9f221b2d..71e1997e7 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -3,10 +3,8 @@ #include +#include #include -#include -#include -#include #include #include #include diff --git a/include/llmr/style/types.hpp b/include/llmr/style/types.hpp index 9bd84d142..f10a0f3dc 100644 --- a/include/llmr/style/types.hpp +++ b/include/llmr/style/types.hpp @@ -15,6 +15,11 @@ enum class BucketType : uint8_t { Default = None }; +BucketType parseBucketType(const std::string &type); +const char *stringifyBucketType(BucketType type); +std::ostream& operator<<(std::ostream&, BucketType type); + + enum class WindingType : uint8_t { EvenOdd, NonZero, @@ -63,15 +68,6 @@ enum class SourceType : uint8_t { Default = Vector }; -inline BucketType parseBucketType(const std::string &type) { - if (type == "fill") return BucketType::Fill; - if (type == "line") return BucketType::Line; - if (type == "icon") return BucketType::Icon; - if (type == "text") return BucketType::Text; - if (type == "raster") return BucketType::Raster; - return BucketType::None; -} - inline WindingType parseWindingType(const std::string &type) { if (type == "even-odd") return WindingType::EvenOdd; if (type == "non-zero") return WindingType::NonZero; diff --git a/src/map/vector_tile.cpp b/src/map/vector_tile.cpp index 54a971cd8..fb4272668 100644 --- a/src/map/vector_tile.cpp +++ b/src/map/vector_tile.cpp @@ -1,5 +1,4 @@ #include -#include #include #include diff --git a/src/style/bucket_description.cpp b/src/style/bucket_description.cpp deleted file mode 100644 index 22e7898e0..000000000 --- a/src/style/bucket_description.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include - -std::ostream& llmr::operator<<(std::ostream& os, BucketType type) { - switch (type) { - case BucketType::None: os << "None"; return os; - case BucketType::Fill: os << "Fill"; return os; - case BucketType::Line: os << "Line"; return os; - case BucketType::Icon: os << "Icon"; return os; - case BucketType::Text: os << "Text"; return os; - case BucketType::Raster: os << "Raster"; return os; - default: os << ""; return os; - } -} \ No newline at end of file diff --git a/src/style/class_description.cpp b/src/style/class_description.cpp deleted file mode 100644 index 48cf63930..000000000 --- a/src/style/class_description.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -namespace llmr { - -void ClassDescription::addClass(const std::string &name, ClassProperties &&properties) { - styles.emplace(name, std::move(properties)); -} - -} diff --git a/src/style/layer_description.cpp b/src/style/layer_description.cpp deleted file mode 100644 index 7e5ca5820..000000000 --- a/src/style/layer_description.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include - -#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; -//} diff --git a/src/style/types.cpp b/src/style/types.cpp new file mode 100644 index 000000000..6cedbb1ab --- /dev/null +++ b/src/style/types.cpp @@ -0,0 +1,31 @@ +#include + +#include + +namespace llmr { + +BucketType parseBucketType(const std::string &type) { + if (type == "fill") return BucketType::Fill; + if (type == "line") return BucketType::Line; + if (type == "icon") return BucketType::Icon; + if (type == "text") return BucketType::Text; + if (type == "raster") return BucketType::Raster; + return BucketType::None; +} + +const char *stringifyBucketType(BucketType type) { + switch (type) { + case BucketType::Fill: return "fill"; + case BucketType::Line: return "line"; + case BucketType::Icon: return "icon"; + case BucketType::Text: return "text"; + case BucketType::Raster: return "raster"; + default: return "none"; + } +} + +std::ostream& operator<<(std::ostream& os, BucketType type) { + return os << stringifyBucketType(type); +} + +} diff --git a/src/text/placement.cpp b/src/text/placement.cpp index 57b7901b8..aef5288bf 100644 --- a/src/text/placement.cpp +++ b/src/text/placement.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include From 6d9de7573202d4b2332667f2d685a0e73e7c0f52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 27 Jun 2014 15:52:45 +0200 Subject: [PATCH 13/55] rename time => timestamp to avoid naming conflicts --- include/llmr/map/map.hpp | 6 ++-- include/llmr/map/source.hpp | 2 +- include/llmr/map/transform.hpp | 26 ++++++++--------- include/llmr/renderer/frame_history.hpp | 6 ++-- include/llmr/style/style.hpp | 2 +- include/llmr/util/raster.hpp | 2 +- include/llmr/util/time.hpp | 36 +++++++++++------------ include/llmr/util/transition.hpp | 16 +++++------ src/map/transform.cpp | 38 ++++++++++++------------- src/renderer/frame_history.cpp | 4 +-- src/renderer/painter_text.cpp | 4 +-- src/style/style.cpp | 2 +- src/util/raster.cpp | 4 +-- src/util/timer.cpp | 2 +- src/util/transition.cpp | 8 +++--- 15 files changed, 79 insertions(+), 79 deletions(-) diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index 2c412bd45..621fdb388 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -105,8 +105,8 @@ public: inline std::shared_ptr getSpriteAtlas() { return spriteAtlas; } inline std::shared_ptr getTexturepool() { return texturepool; } inline std::shared_ptr getLoop() { return loop; } - inline time getAnimationTime() const { return animationTime; } - inline time getTime() const { return animationTime; } + inline timestamp getAnimationTime() const { return animationTime; } + inline timestamp getTime() const { return animationTime; } private: // uv async callbacks @@ -163,7 +163,7 @@ private: std::string styleJSON = ""; bool debug = false; - time animationTime = 0; + timestamp animationTime = 0; int indent = 0; diff --git a/include/llmr/map/source.hpp b/include/llmr/map/source.hpp index c27250858..93dabdc7c 100644 --- a/include/llmr/map/source.hpp +++ b/include/llmr/map/source.hpp @@ -58,7 +58,7 @@ private: private: // Stores the time when this source was most recently updated. - time updated = 0; + timestamp updated = 0; std::map> tiles; std::map> tile_data; diff --git a/include/llmr/map/transform.hpp b/include/llmr/map/transform.hpp index 63b75d43d..c4474ff02 100644 --- a/include/llmr/map/transform.hpp +++ b/include/llmr/map/transform.hpp @@ -23,18 +23,18 @@ public: uint16_t fb_width, uint16_t fb_height); // Position - void moveBy(double dx, double dy, time duration = 0); - void setLonLat(double lon, double lat, time duration = 0); - void setLonLatZoom(double lon, double lat, double zoom, time duration = 0); + void moveBy(double dx, double dy, timestamp duration = 0); + void setLonLat(double lon, double lat, timestamp duration = 0); + void setLonLatZoom(double lon, double lat, double zoom, timestamp duration = 0); void getLonLat(double& lon, double& lat) const; void getLonLatZoom(double& lon, double& lat, double& zoom) const; void startPanning(); void stopPanning(); // Zoom - void scaleBy(double ds, double cx = -1, double cy = -1, time duration = 0); - void setScale(double scale, double cx = -1, double cy = -1, time duration = 0); - void setZoom(double zoom, time duration = 0); + void scaleBy(double ds, double cx = -1, double cy = -1, timestamp duration = 0); + void setScale(double scale, double cx = -1, double cy = -1, timestamp duration = 0); + void setZoom(double zoom, timestamp duration = 0); double getZoom() const; double getScale() const; void startScaling(); @@ -43,8 +43,8 @@ public: double getMaxZoom() const; // Angle - void rotateBy(double sx, double sy, double ex, double ey, time duration = 0); - void setAngle(double angle, time duration = 0); + void rotateBy(double sx, double sy, double ex, double ey, timestamp duration = 0); + void setAngle(double angle, timestamp duration = 0); void setAngle(double angle, double cx, double cy); double getAngle() const; void startRotating(); @@ -53,7 +53,7 @@ public: // Transitions bool needsTransition() const; - void updateTransitions(time now); + void updateTransitions(timestamp now); void cancelTransitions(); // Transform state @@ -63,10 +63,10 @@ public: private: // Functions prefixed with underscores will *not* perform any locks. It is the caller's // responsibility to lock this object. - void _moveBy(double dx, double dy, time duration = 0); - void _setScale(double scale, double cx, double cy, time duration = 0); - void _setScaleXY(double new_scale, double xn, double yn, time duration = 0); - void _setAngle(double angle, time duration = 0); + void _moveBy(double dx, double dy, timestamp duration = 0); + void _setScale(double scale, double cx, double cy, timestamp duration = 0); + void _setScaleXY(double new_scale, double xn, double yn, timestamp duration = 0); + void _setAngle(double angle, timestamp duration = 0); void _clearPanning(); void _clearRotating(); void _clearScaling(); diff --git a/include/llmr/renderer/frame_history.hpp b/include/llmr/renderer/frame_history.hpp index e45bd527b..412fce92b 100644 --- a/include/llmr/renderer/frame_history.hpp +++ b/include/llmr/renderer/frame_history.hpp @@ -11,7 +11,7 @@ namespace llmr { struct FrameSnapshot { - explicit inline FrameSnapshot(time timestamp, float z) : timestamp(timestamp), z(z) {} + explicit inline FrameSnapshot(timestamp timestamp, float z) : timestamp(timestamp), z(z) {} float timestamp; float z; }; @@ -19,9 +19,9 @@ struct FrameSnapshot { class FrameHistory { public: // Record frame history that will be used to calculate fading params - void record(time now, float zoom); + void record(timestamp now, float zoom); - bool needsAnimation(time duration) const; + bool needsAnimation(timestamp duration) const; public: std::deque history; diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index 71e1997e7..73ad6d6bd 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -61,7 +61,7 @@ public: void cascade(float z); bool needsTransition() const; - void updateTransitions(time now); + void updateTransitions(timestamp now); void cancelTransitions(); void setDefaultTransitionDuration(uint64_t duration_milliseconds = 0); diff --git a/include/llmr/util/raster.hpp b/include/llmr/util/raster.hpp index fb3857876..cbc342d56 100644 --- a/include/llmr/util/raster.hpp +++ b/include/llmr/util/raster.hpp @@ -31,7 +31,7 @@ public: // transitions void beginFadeInTransition(); bool needsTransition() const; - void updateTransitions(time now); + void updateTransitions(timestamp now); public: // loaded image dimensions diff --git a/include/llmr/util/time.hpp b/include/llmr/util/time.hpp index f9e3cc05c..9a27cdbe3 100644 --- a/include/llmr/util/time.hpp +++ b/include/llmr/util/time.hpp @@ -5,7 +5,7 @@ namespace llmr { -typedef uint64_t time; +typedef uint64_t timestamp; namespace util { @@ -13,29 +13,29 @@ namespace util { // Returns time in nanoseconds since an arbitrary point in the past. This has // no relation to the current time, but is continuously increasing, so // comparisons between different timestamps produce meaningful values. -inline time now() { +inline timestamp now() { return uv_hrtime(); } } // used for time conversions -constexpr time operator"" _nanoseconds (long double ns) { return ns; } -constexpr time operator"" _nanosecond (long double ns) { return ns; } -constexpr time operator"" _microseconds (long double us) { return us * 1e3; } -constexpr time operator"" _microsecond (long double us) { return us * 1e3; } -constexpr time operator"" _milliseconds (long double ms) { return ms * 1e6; } -constexpr time operator"" _millisecond (long double ms) { return ms * 1e6; } -constexpr time operator"" _seconds (long double s) { return s * 1e9; } -constexpr time operator"" _second (long double s) { return s * 1e9; } +constexpr timestamp operator"" _nanoseconds (long double ns) { return ns; } +constexpr timestamp operator"" _nanosecond (long double ns) { return ns; } +constexpr timestamp operator"" _microseconds (long double us) { return us * 1e3; } +constexpr timestamp operator"" _microsecond (long double us) { return us * 1e3; } +constexpr timestamp operator"" _milliseconds (long double ms) { return ms * 1e6; } +constexpr timestamp operator"" _millisecond (long double ms) { return ms * 1e6; } +constexpr timestamp operator"" _seconds (long double s) { return s * 1e9; } +constexpr timestamp operator"" _second (long double s) { return s * 1e9; } -constexpr time operator"" _nanoseconds (unsigned long long ns) { return ns; } -constexpr time operator"" _nanosecond (unsigned long long ns) { return ns; } -constexpr time operator"" _microseconds (unsigned long long us) { return us * 1e3; } -constexpr time operator"" _microsecond (unsigned long long us) { return us * 1e3; } -constexpr time operator"" _milliseconds (unsigned long long ms) { return ms * 1e6; } -constexpr time operator"" _millisecond (unsigned long long ms) { return ms * 1e6; } -constexpr time operator"" _seconds (unsigned long long s) { return s * 1e9; } -constexpr time operator"" _second (unsigned long long s) { return s * 1e9; } +constexpr timestamp operator"" _nanoseconds (unsigned long long ns) { return ns; } +constexpr timestamp operator"" _nanosecond (unsigned long long ns) { return ns; } +constexpr timestamp operator"" _microseconds (unsigned long long us) { return us * 1e3; } +constexpr timestamp operator"" _microsecond (unsigned long long us) { return us * 1e3; } +constexpr timestamp operator"" _milliseconds (unsigned long long ms) { return ms * 1e6; } +constexpr timestamp operator"" _millisecond (unsigned long long ms) { return ms * 1e6; } +constexpr timestamp operator"" _seconds (unsigned long long s) { return s * 1e9; } +constexpr timestamp operator"" _second (unsigned long long s) { return s * 1e9; } } diff --git a/include/llmr/util/transition.hpp b/include/llmr/util/transition.hpp index a981f6e83..3085b3455 100644 --- a/include/llmr/util/transition.hpp +++ b/include/llmr/util/transition.hpp @@ -15,18 +15,18 @@ public: complete }; - inline transition(time start, time duration) + inline transition(timestamp start, timestamp duration) : start(start), duration(duration) {} - inline float progress(time now) const { + inline float progress(timestamp now) const { if (duration == 0) return 1; if (start > now) return 0; return (float)(now - start) / duration; } - virtual state update(time now) const = 0; + virtual state update(timestamp now) const = 0; virtual ~transition(); protected: @@ -36,19 +36,19 @@ protected: std::array interpolateFloatArray(std::array from, std::array to, double t) const; protected: - const time start, duration; + const timestamp start, duration; }; template class ease_transition : public transition { public: - ease_transition(T from, T to, T& value, time start, time duration) + ease_transition(T from, T to, T& value, timestamp start, timestamp duration) : transition(start, duration), from(from), to(to), value(value) {} - state update(time now) const; + state update(timestamp now) const; private: const T from, to; @@ -59,12 +59,12 @@ private: template class timeout : public transition { public: - timeout(T final_value, T& value, time start, time duration) + timeout(T final_value, T& value, timestamp start, timestamp duration) : transition(start, duration), final_value(final_value), value(value) {} - state update(time now) const { + state update(timestamp now) const { if (progress(now) >= 1) { value = final_value; return complete; diff --git a/src/map/transform.cpp b/src/map/transform.cpp index adfa41c39..c7bbbfdf7 100644 --- a/src/map/transform.cpp +++ b/src/map/transform.cpp @@ -44,13 +44,13 @@ bool Transform::resize(const uint16_t w, const uint16_t h, const float ratio, #pragma mark - Position -void Transform::moveBy(const double dx, const double dy, const time duration) { +void Transform::moveBy(const double dx, const double dy, const timestamp duration) { uv::writelock lock(mtx); _moveBy(dx, dy, duration); } -void Transform::_moveBy(const double dx, const double dy, const time duration) { +void Transform::_moveBy(const double dx, const double dy, const timestamp duration) { // This is only called internally, so we don't need a lock here. final.x = current.x + std::cos(current.angle) * dx + std::sin(current.angle) * dy; @@ -69,7 +69,7 @@ void Transform::_moveBy(const double dx, const double dy, const time duration) { current.y = final.y; } else { // Use a common start time for all of the transitions to avoid divergent transitions. - time start = util::now(); + timestamp start = util::now(); transitions.emplace_front( std::make_shared>(current.x, final.x, current.x, start, duration)); transitions.emplace_front( @@ -79,7 +79,7 @@ void Transform::_moveBy(const double dx, const double dy, const time duration) { platform::notify_map_change(); } -void Transform::setLonLat(const double lon, const double lat, const time duration) { +void Transform::setLonLat(const double lon, const double lat, const timestamp duration) { uv::writelock lock(mtx); const double f = std::fmin(std::fmax(std::sin(D2R * lat), -0.9999), 0.9999); @@ -90,7 +90,7 @@ void Transform::setLonLat(const double lon, const double lat, const time duratio } void Transform::setLonLatZoom(const double lon, const double lat, const double zoom, - const time duration) { + const timestamp duration) { uv::writelock lock(mtx); double new_scale = std::pow(2.0, zoom); @@ -128,7 +128,7 @@ void Transform::startPanning() { // Add a 200ms timeout for resetting this to false current.panning = true; - time start = util::now(); + timestamp start = util::now(); pan_timeout = std::make_shared>(false, current.panning, start, 200_milliseconds); transitions.emplace_front(pan_timeout); } @@ -149,7 +149,7 @@ void Transform::_clearPanning() { #pragma mark - Zoom -void Transform::scaleBy(const double ds, const double cx, const double cy, const time duration) { +void Transform::scaleBy(const double ds, const double cx, const double cy, const timestamp duration) { uv::writelock lock(mtx); // clamp scale to min/max values @@ -164,13 +164,13 @@ void Transform::scaleBy(const double ds, const double cx, const double cy, const } void Transform::setScale(const double scale, const double cx, const double cy, - const time duration) { + const timestamp duration) { uv::writelock lock(mtx); _setScale(scale, cx, cy, duration); } -void Transform::setZoom(const double zoom, const time duration) { +void Transform::setZoom(const double zoom, const timestamp duration) { uv::writelock lock(mtx); _setScale(std::pow(2.0, zoom), -1, -1, duration); @@ -195,7 +195,7 @@ void Transform::startScaling() { // Add a 200ms timeout for resetting this to false current.scaling = true; - time start = util::now(); + timestamp start = util::now(); scale_timeout = std::make_shared>(false, current.scaling, start, 200_milliseconds); transitions.emplace_front(scale_timeout); } @@ -228,7 +228,7 @@ void Transform::_clearScaling() { } } -void Transform::_setScale(double new_scale, double cx, double cy, const time duration) { +void Transform::_setScale(double new_scale, double cx, double cy, const timestamp duration) { // This is only called internally, so we don't need a lock here. // Ensure that we don't zoom in further than the maximum allowed. @@ -262,7 +262,7 @@ void Transform::_setScale(double new_scale, double cx, double cy, const time dur } void Transform::_setScaleXY(const double new_scale, const double xn, const double yn, - const time duration) { + const timestamp duration) { // This is only called internally, so we don't need a lock here. final.scale = new_scale; @@ -280,7 +280,7 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl current.y = final.y; } else { // Use a common start time for all of the transitions to avoid divergent transitions. - time start = util::now(); + timestamp start = util::now(); transitions.emplace_front(std::make_shared>( current.scale, final.scale, current.scale, start, duration)); transitions.emplace_front( @@ -313,7 +313,7 @@ void Transform::constrain(double& scale, double& y) const { #pragma mark - Angle void Transform::rotateBy(const double start_x, const double start_y, const double end_x, - const double end_y, const time duration) { + const double end_y, const timestamp duration) { uv::writelock lock(mtx); double center_x = current.width / 2, center_y = current.height / 2; @@ -343,7 +343,7 @@ void Transform::rotateBy(const double start_x, const double start_y, const doubl _setAngle(ang, duration); } -void Transform::setAngle(const double new_angle, const time duration) { +void Transform::setAngle(const double new_angle, const timestamp duration) { uv::writelock lock(mtx); _setAngle(new_angle, duration); @@ -367,7 +367,7 @@ void Transform::setAngle(const double new_angle, const double cx, const double c } } -void Transform::_setAngle(double new_angle, const time duration) { +void Transform::_setAngle(double new_angle, const timestamp duration) { // This is only called internally, so we don't need a lock here. while (new_angle > M_PI) @@ -383,7 +383,7 @@ void Transform::_setAngle(double new_angle, const time duration) { if (duration == 0) { current.angle = final.angle; } else { - time start = util::now(); + timestamp start = util::now(); transitions.emplace_front(std::make_shared>( current.angle, final.angle, current.angle, start, duration)); } @@ -404,7 +404,7 @@ void Transform::startRotating() { // Add a 200ms timeout for resetting this to false current.rotating = true; - time start = util::now(); + timestamp start = util::now(); rotate_timeout = std::make_shared>(false, current.rotating, start, 200_milliseconds); transitions.emplace_front(rotate_timeout); } @@ -437,7 +437,7 @@ bool Transform::needsTransition() const { return !transitions.empty(); } -void Transform::updateTransitions(const time now) { +void Transform::updateTransitions(const timestamp now) { uv::writelock lock(mtx); transitions.remove_if([now](const std::shared_ptr &transition) { diff --git a/src/renderer/frame_history.cpp b/src/renderer/frame_history.cpp index c93d38818..e73eaf626 100644 --- a/src/renderer/frame_history.cpp +++ b/src/renderer/frame_history.cpp @@ -3,7 +3,7 @@ using namespace llmr; // Record frame history that will be used to calculate fading params -void FrameHistory::record(time now, float zoom) { +void FrameHistory::record(timestamp now, float zoom) { // first frame ever if (!history.size()) { history.emplace_back(FrameSnapshot{0, zoom}); @@ -15,7 +15,7 @@ void FrameHistory::record(time now, float zoom) { } } -bool FrameHistory::needsAnimation(const time duration) const { +bool FrameHistory::needsAnimation(const timestamp duration) const { if (!history.size()) { return false; } diff --git a/src/renderer/painter_text.cpp b/src/renderer/painter_text.cpp index 40a4edf89..47fea57c9 100644 --- a/src/renderer/painter_text.cpp +++ b/src/renderer/painter_text.cpp @@ -47,8 +47,8 @@ void Painter::renderText(TextBucket& bucket, std::shared_ptr layer_d textShader->setZoom((map.getState().getNormalizedZoom() - zoomAdjust) * 10); // current zoom level // Label fading - const time duration = 300_milliseconds; - const time currentTime = util::now(); + const timestamp duration = 300_milliseconds; + const timestamp currentTime = util::now(); std::deque &history = frameHistory.history; diff --git a/src/style/style.cpp b/src/style/style.cpp index 87cfd81f8..d0077d719 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -201,7 +201,7 @@ bool Style::needsTransition() const { return false; } -void Style::updateTransitions(time now) { +void Style::updateTransitions(timestamp now) { uv::writelock lock(mtx); } diff --git a/src/util/raster.cpp b/src/util/raster.cpp index 82ac0bda5..d4b64d0ed 100644 --- a/src/util/raster.cpp +++ b/src/util/raster.cpp @@ -69,7 +69,7 @@ void Raster::bind(bool linear) { } void Raster::beginFadeInTransition() { - time start = util::now(); + timestamp start = util::now(); fade_transition = std::make_shared>(opacity, 1.0, opacity, start, 250_milliseconds); } @@ -77,7 +77,7 @@ bool Raster::needsTransition() const { return fade_transition != nullptr; } -void Raster::updateTransitions(time now) { +void Raster::updateTransitions(timestamp now) { if (fade_transition->update(now) == util::transition::complete) { fade_transition = nullptr; } diff --git a/src/util/timer.cpp b/src/util/timer.cpp index 56ad4fbbe..6d4fc1135 100644 --- a/src/util/timer.cpp +++ b/src/util/timer.cpp @@ -18,7 +18,7 @@ timer::timer(const std::string &name) : name(name), start(now()) { } void timer::report(const std::string &name) { - time duration = now() - start; + timestamp duration = now() - start; std::cerr << std::string((indent - 1) * 4, ' ') << name << ": " << (double)(duration) / 1_millisecond diff --git a/src/util/transition.cpp b/src/util/transition.cpp index 7f4b544fe..10f94c78b 100644 --- a/src/util/transition.cpp +++ b/src/util/transition.cpp @@ -28,7 +28,7 @@ std::array transition::interpolateFloatArray(std::array from } template <> -transition::state ease_transition::update(llmr::time now) const { +transition::state ease_transition::update(timestamp now) const { float t = progress(now); if (t >= 1) { value = to; @@ -40,7 +40,7 @@ transition::state ease_transition::update(llmr::time now) const { } template <> -transition::state ease_transition::update(llmr::time now) const { +transition::state ease_transition::update(timestamp now) const { float t = progress(now); if (t >= 1) { value = to; @@ -52,7 +52,7 @@ transition::state ease_transition::update(llmr::time now) const { } template <> -transition::state ease_transition::update(llmr::time now) const { +transition::state ease_transition::update(timestamp now) const { float t = progress(now); if (t >= 1) { value = to; @@ -64,7 +64,7 @@ transition::state ease_transition::update(llmr::time now) const { } template <> -transition::state ease_transition>::update(llmr::time now) const { +transition::state ease_transition>::update(timestamp now) const { float t = progress(now); if (t >= 1) { value = to; From e989478b27598cfac60a0ee20d1d5cef71d8accb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 27 Jun 2014 15:53:12 +0200 Subject: [PATCH 14/55] add class dictionary to avoid storing strings all the time --- include/llmr/style/class_dictionary.hpp | 32 +++++++++++++++++++++++++ src/style/class_dictionary.cpp | 29 ++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 include/llmr/style/class_dictionary.hpp create mode 100644 src/style/class_dictionary.cpp diff --git a/include/llmr/style/class_dictionary.hpp b/include/llmr/style/class_dictionary.hpp new file mode 100644 index 000000000..772eb9c70 --- /dev/null +++ b/include/llmr/style/class_dictionary.hpp @@ -0,0 +1,32 @@ +#ifndef LLMR_STYLE_CLASS_DICTIONARY +#define LLMR_STYLE_CLASS_DICTIONARY + +#include +#include +#include + +namespace llmr { + +enum class ClassID : uint32_t { + Fallback = 0, // These values are from the fallback properties + Default = 1, // These values are from the default style for a layer + Named = 2 // These values (and all subsequent IDs) are from a named style from the layer +}; + +class ClassDictionary { +public: + // Returns an ID for a class name. If the class name does not yet have an ID, one is + // auto-generated and stored for future reference. + static ClassID Lookup(const std::string &class_name); + + // Returns either Fallback, Default or Named, depending on the type of the class id. + static ClassID Normalize(ClassID id); + +private: + static std::unordered_map store; + static uint32_t offset; +}; + +} + +#endif diff --git a/src/style/class_dictionary.cpp b/src/style/class_dictionary.cpp new file mode 100644 index 000000000..a641295c6 --- /dev/null +++ b/src/style/class_dictionary.cpp @@ -0,0 +1,29 @@ +#include + +namespace llmr { + +ClassID ClassDictionary::Lookup(const std::string &class_name) { + auto it = store.find(class_name); + if (it == store.end()) { + // Insert the class name into the store. + ClassID id = ClassID(uint32_t(ClassID::Named) + offset++); + store.emplace(class_name, id); + return id; + } else { + return it->second; + } +} + +ClassID ClassDictionary::Normalize(ClassID id) { + if (id >= ClassID::Named) { + return ClassID::Named; + } else { + return id; + } +} + + +std::unordered_map ClassDictionary::store = { { "", ClassID::Default } }; +uint32_t ClassDictionary::offset = 0; + +} From 38d9cd0d4f044090d417be35bf1771380472537c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 27 Jun 2014 15:57:47 +0200 Subject: [PATCH 15/55] use class ids rather than names for storing styles --- include/llmr/style/style.hpp | 3 ++- src/style/style.cpp | 5 +++-- src/style/style_parser.cpp | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index 73ad6d6bd..fd5f7e222 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -38,7 +39,7 @@ public: public: std::string id; StyleBucket::Ptr bucket; - std::unordered_map styles; + std::map styles; StyleProperties style; std::unique_ptr rasterize; std::shared_ptr layers; diff --git a/src/style/style.cpp b/src/style/style.cpp index d0077d719..64cdfd659 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -164,14 +164,15 @@ void Style::cascade(const std::shared_ptr &layers, float z) { layer->style = resetClassProperties(*layer); // Apply default class (if exists) - auto default_it = layer->styles.find(""); + auto default_it = layer->styles.find(ClassID::Default); 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); + const ClassID class_id = ClassDictionary::Lookup(class_name); + auto class_it = layer->styles.find(class_id); if (class_it != layer->styles.end()) { applyClassProperties(layer->style, class_it->second, z); } diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 34aa7f222..5d5737567 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -469,9 +469,10 @@ void StyleParser::parseStyles(JSVal value, std::shared_ptr &layer) { const std::string name { itr->name.GetString(), itr->name.GetStringLength() }; if (name == "style") { - parseStyle(replaceConstant(itr->value), layer->styles[""]); + parseStyle(replaceConstant(itr->value), layer->styles[ClassID::Default]); } else if (name.compare(0, 6, "style.") == 0 && name.length() > 6) { - parseStyle(replaceConstant(itr->value), layer->styles[name.substr(6)]); + const ClassID class_id = ClassDictionary::Lookup(name.substr(6)); + parseStyle(replaceConstant(itr->value), layer->styles[class_id]); } } } From ad4497c90994e75dd918e09a201a87ef85d6504c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 27 Jun 2014 16:19:43 +0200 Subject: [PATCH 16/55] reorganize properties --- include/llmr/map/source.hpp | 1 + include/llmr/renderer/painter.hpp | 6 +- include/llmr/renderer/prerendered_texture.hpp | 2 +- include/llmr/style/class_properties.hpp | 121 ++++++++ include/llmr/style/function_properties.hpp | 45 +++ include/llmr/style/properties.hpp | 290 ------------------ include/llmr/style/rasterize_properties.hpp | 26 ++ include/llmr/style/style.hpp | 3 + include/llmr/style/style_properties.hpp | 122 ++++++++ include/llmr/style/types.hpp | 4 + include/llmr/util/transition.hpp | 2 +- src/renderer/painter_composite.cpp | 1 + ...properties.cpp => function_properties.cpp} | 13 +- src/style/style.cpp | 1 - src/style/style_parser.cpp | 1 - src/style/style_properties.cpp | 13 + 16 files changed, 344 insertions(+), 307 deletions(-) create mode 100644 include/llmr/style/class_properties.hpp create mode 100644 include/llmr/style/function_properties.hpp delete mode 100644 include/llmr/style/properties.hpp create mode 100644 include/llmr/style/rasterize_properties.hpp create mode 100644 include/llmr/style/style_properties.hpp rename src/style/{properties.cpp => function_properties.cpp} (75%) create mode 100644 src/style/style_properties.cpp diff --git a/include/llmr/map/source.hpp b/include/llmr/map/source.hpp index 93dabdc7c..0d6ef864f 100644 --- a/include/llmr/map/source.hpp +++ b/include/llmr/map/source.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index 1b1d231ca..3a5f73270 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -25,6 +25,7 @@ #include #include +#include namespace llmr { @@ -40,6 +41,9 @@ class IconBucket; class TextBucket; class RasterBucket; +struct FillProperties; +struct CompositeProperties; + class LayerDescription; class RasterTileData; diff --git a/include/llmr/renderer/prerendered_texture.hpp b/include/llmr/renderer/prerendered_texture.hpp index b109e397c..6ca3cd540 100644 --- a/include/llmr/renderer/prerendered_texture.hpp +++ b/include/llmr/renderer/prerendered_texture.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include namespace llmr { diff --git a/include/llmr/style/class_properties.hpp b/include/llmr/style/class_properties.hpp new file mode 100644 index 000000000..92f7fa3f4 --- /dev/null +++ b/include/llmr/style/class_properties.hpp @@ -0,0 +1,121 @@ +#ifndef LLMR_STYLE_CLASS_PROPERTIES +#define LLMR_STYLE_CLASS_PROPERTIES + +#include +#include +#include + + +#include + +namespace llmr { + +enum class ClassPropertyKey { + FillEnabled, + FillAntialias, + FillOpacity, + FillColor, + FillOutlineColor, + FillTranslate, // for transitions only + FillTranslateX, + FillTranslateY, + FillTranslateAnchor, + FillImage, + + LineEnabled, + LineOpacity, + LineColor, + LineTranslate, // for transitions only + LineTranslateX, + LineTranslateY, + LineTranslateAnchor, + LineWidth, + LineOffset, + LineBlur, + LineDashArray, // for transitions only + LineDashLand, + LineDashGap, + LineImage, + + IconEnabled, + IconOpacity, + IconRotate, + IconRotateAnchor, + + TextEnabled, + TextOpacity, + TextSize, + TextColor, + TextHaloColor, + TextHaloWidth, + TextHaloBlur, + + CompositeEnabled, + CompositeOpacity, + + RasterSpin, + RasterBrightnessLow, + RasterBrightnessHigh, + RasterSaturation, + RasterContrast, + RasterFade, + + BackgroundColor +}; + +typedef util::variant< + FunctionProperty, + TranslateAnchorType, + RotateAnchorType, + Color, + std::string, + bool +> ClassPropertyValue; + + +struct ClassPropertyTransition { + uint16_t duration = 0; + uint16_t delay = 0; +}; + +class ClassProperties { +public: + inline ClassProperties() {} + inline ClassProperties(ClassProperties &&properties) + : properties(std::move(properties.properties)) {} + + template + inline const T *get(ClassPropertyKey key) const { + const auto it = properties.find(key); + if (it != properties.end() && it->second.is()) { + return ::std::addressof(it->second.get()); + } else { + return nullptr; + } + } + 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; + } + } + + template + inline void set(Args&& ...args) { + properties.emplace(::std::forward(args)...); + } + template + inline void setTransition(Args&& ...args) { + transitions.emplace(::std::forward(args)...); + } + +public: + std::map properties; + std::map transitions; +}; + +} + +#endif diff --git a/include/llmr/style/function_properties.hpp b/include/llmr/style/function_properties.hpp new file mode 100644 index 000000000..970d617d0 --- /dev/null +++ b/include/llmr/style/function_properties.hpp @@ -0,0 +1,45 @@ +#ifndef LLMR_STYLE_FUNCTION_PROPERTIES +#define LLMR_STYLE_FUNCTION_PROPERTIES + +#include + +namespace llmr { + +namespace functions { + +float null(float z, const std::vector&); +float constant(float z, const std::vector& values); +float min(float z, const std::vector& values); +float max(float z, const std::vector& values); +float stops(float z, const std::vector& values); +float linear(float z, const std::vector& values); +float exponential(float z, const std::vector& values); + +} + +struct FunctionProperty { + typedef float (*fn)(float z, const std::vector& values); + + fn function; + std::vector values; + + inline FunctionProperty() : function(&functions::null) {} + + inline FunctionProperty(const FunctionProperty &property) + : function(property.function), values(property.values) {} + inline FunctionProperty(FunctionProperty &&property) + : function(property.function), values(std::move(property.values)) {} + + + inline void operator=(const FunctionProperty &rhs) { + function = rhs.function; + values = rhs.values; + } + + inline FunctionProperty(float value) : function(&functions::constant), values(1, value) {} + template inline T evaluate(float z) const { return function(z, values); } +}; + +} + +#endif diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp deleted file mode 100644 index 32ef18760..000000000 --- a/include/llmr/style/properties.hpp +++ /dev/null @@ -1,290 +0,0 @@ -#ifndef LLMR_STYLE_PROPERTIES -#define LLMR_STYLE_PROPERTIES - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -namespace llmr { - -// Stores a premultiplied color, with all four channels ranging from 0..1 -typedef std::array Color; - -struct ClassPropertyTransition { - uint16_t duration = 0; - uint16_t delay = 0; -}; - -enum class Property { - Null = 1, - Constant = 2, - Stops = 3, - Linear = 4 -}; -namespace functions { - -float null(float z, const std::vector&); -float constant(float z, const std::vector& values); -float min(float z, const std::vector& values); -float max(float z, const std::vector& values); -float stops(float z, const std::vector& values); -float linear(float z, const std::vector& values); -float exponential(float z, const std::vector& values); - -} - -struct FunctionProperty { - typedef float (*fn)(float z, const std::vector& values); - - fn function; - std::vector values; - - inline FunctionProperty() : function(&functions::null) {} - - inline FunctionProperty(const FunctionProperty &property) - : function(property.function), values(property.values) {} - inline FunctionProperty(FunctionProperty &&property) - : function(property.function), values(std::move(property.values)) {} - - - inline void operator=(const FunctionProperty &rhs) { - function = rhs.function; - values = rhs.values; - } - - inline FunctionProperty(float value) : function(&functions::constant), values(1, value) {} - template inline T evaluate(float z) const { return function(z, values); } -}; - -enum class ClassPropertyKey { - FillEnabled, - FillAntialias, - FillOpacity, - FillColor, - FillOutlineColor, - FillTranslate, // for transitions only - FillTranslateX, - FillTranslateY, - FillTranslateAnchor, - FillImage, - - LineEnabled, - LineOpacity, - LineColor, - LineTranslate, // for transitions only - LineTranslateX, - LineTranslateY, - LineTranslateAnchor, - LineWidth, - LineOffset, - LineBlur, - LineDashArray, // for transitions only - LineDashLand, - LineDashGap, - LineImage, - - IconEnabled, - IconOpacity, - IconRotate, - IconRotateAnchor, - - TextEnabled, - TextOpacity, - TextSize, - TextColor, - TextHaloColor, - TextHaloWidth, - TextHaloBlur, - - CompositeEnabled, - CompositeOpacity, - - RasterSpin, - RasterBrightnessLow, - RasterBrightnessHigh, - RasterSaturation, - RasterContrast, - RasterFade, - - BackgroundColor -}; - -typedef util::variant< - FunctionProperty, - TranslateAnchorType, - RotateAnchorType, - Color, - std::string, - bool -> ClassPropertyValue; - -class ClassProperties { -public: - inline ClassProperties() {} - inline ClassProperties(ClassProperties &&properties) - : properties(std::move(properties.properties)) {} - - template - inline const T *get(ClassPropertyKey key) const { - const auto it = properties.find(key); - if (it != properties.end() && it->second.is()) { - return ::std::addressof(it->second.get()); - } else { - return nullptr; - } - } - 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; - } - } - - template - inline void set(Args&& ...args) { - properties.emplace(::std::forward(args)...); - } - template - inline void setTransition(Args&& ...args) { - transitions.emplace(::std::forward(args)...); - } - -public: - std::map properties; - std::map transitions; -}; - -struct PrerenderProperties { - float buffer = 1.0f / 32.0f; - uint16_t size = 256; - uint16_t blur = 0; -}; - -struct FillProperties { - FillProperties() {} - bool enabled = true; - bool antialias = true; - float opacity = 1.0f; - Color fill_color = {{ 0, 0, 0, 1 }}; - Color stroke_color = {{ 0, 0, 0, -1 }}; - std::array translate = {{ 0, 0 }}; - TranslateAnchorType translateAnchor = TranslateAnchorType::Default; - std::string image; - - inline bool isVisible() const { - return enabled && opacity > 0 && (fill_color[3] > 0 || stroke_color[3] > 0); - } -}; - -struct LineProperties { - inline LineProperties() {} - bool enabled = true; - float opacity = 1.0f; - Color color = {{ 0, 0, 0, 1 }}; - std::array translate = {{ 0, 0 }}; - TranslateAnchorType translateAnchor = TranslateAnchorType::Default; - 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 IconProperties { - inline IconProperties() {} - bool enabled = true; - float opacity = 1.0f; - float rotate = 0.0f; - RotateAnchorType rotate_anchor = RotateAnchorType::Default; - - 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 }}; -}; - -typedef util::variant< - FillProperties, - LineProperties, - IconProperties, - TextProperties, - CompositeProperties, - RasterProperties, - BackgroundProperties, - std::false_type -> StyleProperties; - -template -const T &defaultStyleProperties(); - -class RasterizeProperties { -public: - boost::optional enabled; - boost::optional buffer; - boost::optional size; - boost::optional blur; -}; - -} - -#endif diff --git a/include/llmr/style/rasterize_properties.hpp b/include/llmr/style/rasterize_properties.hpp new file mode 100644 index 000000000..f085a7bdd --- /dev/null +++ b/include/llmr/style/rasterize_properties.hpp @@ -0,0 +1,26 @@ +#ifndef LLMR_STYLE_RASTERIZE_PROPERTIES +#define LLMR_STYLE_RASTERIZE_PROPERTIES + +#include + +#include + +namespace llmr { + +struct PrerenderProperties { + float buffer = 1.0f / 32.0f; + uint16_t size = 256; + uint16_t blur = 0; +}; + +class RasterizeProperties { +public: + boost::optional enabled; + boost::optional buffer; + boost::optional size; + boost::optional blur; +}; + +} + +#endif diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index fd5f7e222..f2b4cd492 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include #include #include diff --git a/include/llmr/style/style_properties.hpp b/include/llmr/style/style_properties.hpp new file mode 100644 index 000000000..71758563a --- /dev/null +++ b/include/llmr/style/style_properties.hpp @@ -0,0 +1,122 @@ +#ifndef LLMR_STYLE_STYLE_PROPERTIES +#define LLMR_STYLE_STYLE_PROPERTIES + +#include +#include +#include + +#include +#include +#include +#include + +namespace llmr { + +struct FillProperties { + FillProperties() {} + bool enabled = true; + bool antialias = true; + float opacity = 1.0f; + Color fill_color = {{ 0, 0, 0, 1 }}; + Color stroke_color = {{ 0, 0, 0, -1 }}; + std::array translate = {{ 0, 0 }}; + TranslateAnchorType translateAnchor = TranslateAnchorType::Default; + std::string image; + + inline bool isVisible() const { + return enabled && opacity > 0 && (fill_color[3] > 0 || stroke_color[3] > 0); + } +}; + +struct LineProperties { + inline LineProperties() {} + bool enabled = true; + float opacity = 1.0f; + Color color = {{ 0, 0, 0, 1 }}; + std::array translate = {{ 0, 0 }}; + TranslateAnchorType translateAnchor = TranslateAnchorType::Default; + 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 IconProperties { + inline IconProperties() {} + bool enabled = true; + float opacity = 1.0f; + float rotate = 0.0f; + RotateAnchorType rotate_anchor = RotateAnchorType::Default; + + 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 }}; +}; + +typedef util::variant< + FillProperties, + LineProperties, + IconProperties, + TextProperties, + CompositeProperties, + RasterProperties, + BackgroundProperties, + std::false_type +> StyleProperties; + +template +const T &defaultStyleProperties(); + +} + +#endif diff --git a/include/llmr/style/types.hpp b/include/llmr/style/types.hpp index f10a0f3dc..95365947f 100644 --- a/include/llmr/style/types.hpp +++ b/include/llmr/style/types.hpp @@ -2,9 +2,13 @@ #define LLMR_STYLE_TYPES #include +#include namespace llmr { +// Stores a premultiplied color, with all four channels ranging from 0..1 +typedef std::array Color; + enum class BucketType : uint8_t { None, Fill, diff --git a/include/llmr/util/transition.hpp b/include/llmr/util/transition.hpp index 3085b3455..fbf33d10f 100644 --- a/include/llmr/util/transition.hpp +++ b/include/llmr/util/transition.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include namespace llmr { namespace util { diff --git a/src/renderer/painter_composite.cpp b/src/renderer/painter_composite.cpp index af3fd8e32..4ed507667 100644 --- a/src/renderer/painter_composite.cpp +++ b/src/renderer/painter_composite.cpp @@ -1,4 +1,5 @@ #include +#include #include diff --git a/src/style/properties.cpp b/src/style/function_properties.cpp similarity index 75% rename from src/style/properties.cpp rename to src/style/function_properties.cpp index 4f0649b22..eaaa2ad6f 100644 --- a/src/style/properties.cpp +++ b/src/style/function_properties.cpp @@ -1,8 +1,5 @@ -#include -#include +#include - -#include #include namespace llmr { @@ -86,12 +83,4 @@ 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 64cdfd659..d6d7a7291 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 5d5737567..7bb05ecc6 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/src/style/style_properties.cpp b/src/style/style_properties.cpp new file mode 100644 index 000000000..f2b5af651 --- /dev/null +++ b/src/style/style_properties.cpp @@ -0,0 +1,13 @@ +#include + +namespace llmr { + +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; } + +} From 3d18b84deb99f9c49d355b1ee561bb3d5cc0b144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 27 Jun 2014 16:28:01 +0200 Subject: [PATCH 17/55] add interface for iterating over classproperties --- include/llmr/style/class_properties.hpp | 35 ++++++++++++------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/include/llmr/style/class_properties.hpp b/include/llmr/style/class_properties.hpp index 92f7fa3f4..f355ede22 100644 --- a/include/llmr/style/class_properties.hpp +++ b/include/llmr/style/class_properties.hpp @@ -84,24 +84,6 @@ public: inline ClassProperties(ClassProperties &&properties) : properties(std::move(properties.properties)) {} - template - inline const T *get(ClassPropertyKey key) const { - const auto it = properties.find(key); - if (it != properties.end() && it->second.is()) { - return ::std::addressof(it->second.get()); - } else { - return nullptr; - } - } - 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; - } - } - template inline void set(Args&& ...args) { properties.emplace(::std::forward(args)...); @@ -111,6 +93,23 @@ public: transitions.emplace(::std::forward(args)...); } + inline const ClassPropertyTransition &getTransition(ClassPropertyKey key, const ClassPropertyTransition &defaultTransition) const { + auto it = transitions.find(key); + if (it == transitions.end()) { + return defaultTransition; + } else { + return it->second; + } + } + + // Route-through iterable interface so that you can iterate on the object as is. + inline std::map::const_iterator begin() const { + return properties.begin(); + } + inline std::map::const_iterator end() const { + return properties.end(); + } + public: std::map properties; std::map transitions; From d75f0075f3356f8c0b8616ae93a9973d01cfbcfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 27 Jun 2014 16:42:44 +0200 Subject: [PATCH 18/55] even more refactoring --- include/llmr/map/map.hpp | 1 + include/llmr/map/tile_parser.hpp | 2 +- include/llmr/map/vector_tile.hpp | 2 +- .../llmr/{map => style}/filter_expression.hpp | 4 +- include/llmr/style/style.hpp | 35 +------------- include/llmr/style/style_bucket.hpp | 2 +- include/llmr/style/style_layer.hpp | 46 +++++++++++++++++++ include/llmr/style/style_parser.hpp | 3 ++ src/map/map.cpp | 3 ++ src/map/source.cpp | 1 + src/map/tile_parser.cpp | 1 + src/map/vector_tile_data.cpp | 2 + src/renderer/icon_bucket.cpp | 1 + src/renderer/painter.cpp | 1 + src/renderer/painter_fill.cpp | 1 + src/renderer/painter_icon.cpp | 2 + src/renderer/painter_line.cpp | 1 + src/renderer/painter_raster.cpp | 1 + src/renderer/painter_text.cpp | 1 + src/{map => style}/filter_expression.cpp | 2 +- src/style/style.cpp | 3 +- src/style/style_parser.cpp | 1 + 22 files changed, 76 insertions(+), 40 deletions(-) rename include/llmr/{map => style}/filter_expression.hpp (97%) create mode 100644 include/llmr/style/style_layer.hpp rename src/{map => style}/filter_expression.cpp (99%) diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index 621fdb388..54cbdcb16 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -20,6 +20,7 @@ namespace llmr { class Source; +class SpriteAtlas; class Map : private util::noncopyable { public: diff --git a/include/llmr/map/tile_parser.hpp b/include/llmr/map/tile_parser.hpp index 2809c6b4e..c4fd3d8bc 100644 --- a/include/llmr/map/tile_parser.hpp +++ b/include/llmr/map/tile_parser.hpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include namespace llmr { diff --git a/include/llmr/map/vector_tile.hpp b/include/llmr/map/vector_tile.hpp index f9e01c38b..ad7a0eea1 100644 --- a/include/llmr/map/vector_tile.hpp +++ b/include/llmr/map/vector_tile.hpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/llmr/map/filter_expression.hpp b/include/llmr/style/filter_expression.hpp similarity index 97% rename from include/llmr/map/filter_expression.hpp rename to include/llmr/style/filter_expression.hpp index 3c4ac857e..696aa04ae 100644 --- a/include/llmr/map/filter_expression.hpp +++ b/include/llmr/style/filter_expression.hpp @@ -1,5 +1,5 @@ -#ifndef LLMR_MAP_FILTER_EXPRESSION -#define LLMR_MAP_FILTER_EXPRESSION +#ifndef LLMR_STYLE_FILTER_EXPRESSION +#define LLMR_STYLE_FILTER_EXPRESSION #include #include diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index f2b4cd492..383aa5d75 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -3,15 +3,8 @@ #include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include #include #include @@ -22,34 +15,10 @@ namespace llmr { class Sprite; - +class Source; 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::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) {} }; diff --git a/include/llmr/style/style_bucket.hpp b/include/llmr/style/style_bucket.hpp index eee9929a8..1e3cb2db0 100644 --- a/include/llmr/style/style_bucket.hpp +++ b/include/llmr/style/style_bucket.hpp @@ -2,7 +2,7 @@ #define LLMR_STYLE_STYLE_BUCKET #include -#include +#include #include #include diff --git a/include/llmr/style/style_layer.hpp b/include/llmr/style/style_layer.hpp new file mode 100644 index 000000000..889cd8648 --- /dev/null +++ b/include/llmr/style/style_layer.hpp @@ -0,0 +1,46 @@ +#ifndef LLMR_STYLE_STYLE_LAYER +#define LLMR_STYLE_STYLE_LAYER + +#include +#include +#include + +#include +#include +#include +#include + +namespace llmr { + +class StyleBucket; +class RasterizeProperties; + +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; + std::shared_ptr bucket; + std::map styles; + StyleProperties style; + std::unique_ptr rasterize; + std::shared_ptr layers; +}; + + +} + +#endif diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 29a41fb14..8d7865369 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include #include #include diff --git a/src/map/map.cpp b/src/map/map.cpp index db94ca97d..44c62eeb2 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include #include #include diff --git a/src/map/source.cpp b/src/map/source.cpp index b03d83ca4..6f7bb811f 100644 --- a/src/map/source.cpp +++ b/src/map/source.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index e834e6fa9..847c57d08 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include diff --git a/src/map/vector_tile_data.cpp b/src/map/vector_tile_data.cpp index de99bb5d3..051ebb7ea 100644 --- a/src/map/vector_tile_data.cpp +++ b/src/map/vector_tile_data.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include using namespace llmr; diff --git a/src/renderer/icon_bucket.cpp b/src/renderer/icon_bucket.cpp index 1a1c10450..9cc1407e6 100644 --- a/src/renderer/icon_bucket.cpp +++ b/src/renderer/icon_bucket.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 0739eea32..665c7baec 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include diff --git a/src/renderer/painter_fill.cpp b/src/renderer/painter_fill.cpp index fa79cb8de..e651d3f36 100644 --- a/src/renderer/painter_fill.cpp +++ b/src/renderer/painter_fill.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include diff --git a/src/renderer/painter_icon.cpp b/src/renderer/painter_icon.cpp index f720a2400..59ae67746 100644 --- a/src/renderer/painter_icon.cpp +++ b/src/renderer/painter_icon.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include using namespace llmr; diff --git a/src/renderer/painter_line.cpp b/src/renderer/painter_line.cpp index 6ec7a1e7e..990c80b89 100644 --- a/src/renderer/painter_line.cpp +++ b/src/renderer/painter_line.cpp @@ -1,5 +1,6 @@ #include #include +#include #include using namespace llmr; diff --git a/src/renderer/painter_raster.cpp b/src/renderer/painter_raster.cpp index 4cfe7c0c6..8f330898d 100644 --- a/src/renderer/painter_raster.cpp +++ b/src/renderer/painter_raster.cpp @@ -1,5 +1,6 @@ #include #include +#include #include using namespace llmr; diff --git a/src/renderer/painter_text.cpp b/src/renderer/painter_text.cpp index 47fea57c9..89c9d4107 100644 --- a/src/renderer/painter_text.cpp +++ b/src/renderer/painter_text.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include diff --git a/src/map/filter_expression.cpp b/src/style/filter_expression.cpp similarity index 99% rename from src/map/filter_expression.cpp rename to src/style/filter_expression.cpp index 9e293b002..a0454d8af 100644 --- a/src/map/filter_expression.cpp +++ b/src/style/filter_expression.cpp @@ -1,4 +1,4 @@ -#include +#include #include namespace llmr { diff --git a/src/style/style.cpp b/src/style/style.cpp index d6d7a7291..f6de8c013 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -1,5 +1,7 @@ #include +#include #include +#include #include #include @@ -194,7 +196,6 @@ void Style::cascade(float z) { } } - bool Style::needsTransition() const { uv::readlock lock(mtx); diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 7bb05ecc6..1bbb4fd52 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include From 0e9e2972755b05ddc3e7ab073bb4f9c10377d83c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 27 Jun 2014 16:59:42 +0200 Subject: [PATCH 19/55] more refactoring and fallback values --- .../llmr/style/applied_class_properties.hpp | 41 +++++++++ include/llmr/style/class_properties.hpp | 79 ++-------------- include/llmr/style/property_fallback.hpp | 29 ++++++ include/llmr/style/property_key.hpp | 61 +++++++++++++ include/llmr/style/property_value.hpp | 21 +++++ include/llmr/style/style_parser.hpp | 4 +- src/style/property_fallback.cpp | 13 +++ src/style/style.cpp | 90 +++++++++---------- src/style/style_parser.cpp | 18 ++-- 9 files changed, 228 insertions(+), 128 deletions(-) create mode 100644 include/llmr/style/applied_class_properties.hpp create mode 100644 include/llmr/style/property_fallback.hpp create mode 100644 include/llmr/style/property_key.hpp create mode 100644 include/llmr/style/property_value.hpp create mode 100644 src/style/property_fallback.cpp diff --git a/include/llmr/style/applied_class_properties.hpp b/include/llmr/style/applied_class_properties.hpp new file mode 100644 index 000000000..f90102200 --- /dev/null +++ b/include/llmr/style/applied_class_properties.hpp @@ -0,0 +1,41 @@ +#ifndef LLMR_STYLE_APPLIED_CLASS_PROPERTIES +#define LLMR_STYLE_APPLIED_CLASS_PROPERTIES + +#include +#include +#include + +#include + +namespace llmr { + +class AppliedClassProperty { +public: + AppliedClassProperty(ClassID class_id, timestamp begin, timestamp end, const PropertyValue &value); + +public: + ClassID name; + timestamp begin; + timestamp end; + PropertyValue value; +}; + + +class AppliedClassProperties { +public: + std::list properties; + +public: + // Returns thie ID of the most recent + ClassID mostRecent() const { + return properties.size() ? properties.back().name : ClassID::Fallback; + } + + void add(ClassID class_id, timestamp begin, timestamp end, const PropertyValue &value) { + properties.emplace_back(class_id, begin, end, value); + } +}; + +} + +#endif diff --git a/include/llmr/style/class_properties.hpp b/include/llmr/style/class_properties.hpp index f355ede22..79b16e51a 100644 --- a/include/llmr/style/class_properties.hpp +++ b/include/llmr/style/class_properties.hpp @@ -1,78 +1,13 @@ #ifndef LLMR_STYLE_CLASS_PROPERTIES #define LLMR_STYLE_CLASS_PROPERTIES -#include -#include -#include - +#include +#include #include namespace llmr { -enum class ClassPropertyKey { - FillEnabled, - FillAntialias, - FillOpacity, - FillColor, - FillOutlineColor, - FillTranslate, // for transitions only - FillTranslateX, - FillTranslateY, - FillTranslateAnchor, - FillImage, - - LineEnabled, - LineOpacity, - LineColor, - LineTranslate, // for transitions only - LineTranslateX, - LineTranslateY, - LineTranslateAnchor, - LineWidth, - LineOffset, - LineBlur, - LineDashArray, // for transitions only - LineDashLand, - LineDashGap, - LineImage, - - IconEnabled, - IconOpacity, - IconRotate, - IconRotateAnchor, - - TextEnabled, - TextOpacity, - TextSize, - TextColor, - TextHaloColor, - TextHaloWidth, - TextHaloBlur, - - CompositeEnabled, - CompositeOpacity, - - RasterSpin, - RasterBrightnessLow, - RasterBrightnessHigh, - RasterSaturation, - RasterContrast, - RasterFade, - - BackgroundColor -}; - -typedef util::variant< - FunctionProperty, - TranslateAnchorType, - RotateAnchorType, - Color, - std::string, - bool -> ClassPropertyValue; - - struct ClassPropertyTransition { uint16_t duration = 0; uint16_t delay = 0; @@ -93,7 +28,7 @@ public: transitions.emplace(::std::forward(args)...); } - inline const ClassPropertyTransition &getTransition(ClassPropertyKey key, const ClassPropertyTransition &defaultTransition) const { + inline const ClassPropertyTransition &getTransition(PropertyKey key, const ClassPropertyTransition &defaultTransition) const { auto it = transitions.find(key); if (it == transitions.end()) { return defaultTransition; @@ -103,16 +38,16 @@ public: } // Route-through iterable interface so that you can iterate on the object as is. - inline std::map::const_iterator begin() const { + inline std::map::const_iterator begin() const { return properties.begin(); } - inline std::map::const_iterator end() const { + inline std::map::const_iterator end() const { return properties.end(); } public: - std::map properties; - std::map transitions; + std::map properties; + std::map transitions; }; } diff --git a/include/llmr/style/property_fallback.hpp b/include/llmr/style/property_fallback.hpp new file mode 100644 index 000000000..eb6bb15c9 --- /dev/null +++ b/include/llmr/style/property_fallback.hpp @@ -0,0 +1,29 @@ +#ifndef LLMR_STYLE_PROPERTY_FALLBACK +#define LLMR_STYLE_PROPERTY_FALLBACK + +#include +#include + +#include + +namespace llmr { + +class PropertyFallbackValue { +public: + static const PropertyValue &Get(PropertyKey key) { + auto it = properties.find(key); + if (it != properties.end()) { + return it->second; + } else { + return defaultProperty; + } + } + +private: + static const std::map properties; + static const PropertyValue defaultProperty; +}; + +} + +#endif diff --git a/include/llmr/style/property_key.hpp b/include/llmr/style/property_key.hpp new file mode 100644 index 000000000..e35587239 --- /dev/null +++ b/include/llmr/style/property_key.hpp @@ -0,0 +1,61 @@ +#ifndef LLMR_STYLE_PROPERTY_KEY +#define LLMR_STYLE_PROPERTY_KEY + +namespace llmr { + +enum class PropertyKey { + FillEnabled, + FillAntialias, + FillOpacity, + FillColor, + FillOutlineColor, + FillTranslate, // for transitions only + FillTranslateX, + FillTranslateY, + FillTranslateAnchor, + FillImage, + + LineEnabled, + LineOpacity, + LineColor, + LineTranslate, // for transitions only + LineTranslateX, + LineTranslateY, + LineTranslateAnchor, + LineWidth, + LineOffset, + LineBlur, + LineDashArray, // for transitions only + LineDashLand, + LineDashGap, + LineImage, + + IconEnabled, + IconOpacity, + IconRotate, + IconRotateAnchor, + + TextEnabled, + TextOpacity, + TextSize, + TextColor, + TextHaloColor, + TextHaloWidth, + TextHaloBlur, + + CompositeEnabled, + CompositeOpacity, + + RasterSpin, + RasterBrightnessLow, + RasterBrightnessHigh, + RasterSaturation, + RasterContrast, + RasterFade, + + BackgroundColor +}; + +} + +#endif diff --git a/include/llmr/style/property_value.hpp b/include/llmr/style/property_value.hpp new file mode 100644 index 000000000..9772258da --- /dev/null +++ b/include/llmr/style/property_value.hpp @@ -0,0 +1,21 @@ +#ifndef LLMR_STYLE_PROPERTY_VALUE +#define LLMR_STYLE_PROPERTY_VALUE + +#include +#include +#include + +namespace llmr { + +typedef util::variant< + FunctionProperty, + TranslateAnchorType, + RotateAnchorType, + Color, + std::string, + bool +> PropertyValue; + +} + +#endif diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 8d7865369..52866f771 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -52,9 +52,9 @@ private: // Parses optional properties into style class properties. template - bool parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); + bool parseStyleProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value); template - bool parseStyleProperty(const char *property_name, const std::vector &keys, ClassProperties &klass, JSVal value); + bool parseStyleProperty(const char *property_name, const std::vector &keys, ClassProperties &klass, JSVal value); FilterExpression parseFilter(JSVal, FilterExpression::Operator op); diff --git a/src/style/property_fallback.cpp b/src/style/property_fallback.cpp new file mode 100644 index 000000000..d322f8c57 --- /dev/null +++ b/src/style/property_fallback.cpp @@ -0,0 +1,13 @@ +#include + +namespace llmr { + +const std::map PropertyFallbackValue::properties = { + { PropertyKey::LineEnabled, true }, + { PropertyKey::LineOpacity, 1.0f }, + { PropertyKey::LineColor, Color({{ 0, 0, 0, 1 }}) }, +}; + +const PropertyValue PropertyFallbackValue::defaultProperty; + +} diff --git a/src/style/style.cpp b/src/style/style.cpp index f6de8c013..df14673f8 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -59,10 +59,10 @@ StyleProperties resetClassProperties(StyleLayer &layer) { } template -void applyProperty(const ClassProperties &properties, ClassPropertyKey key, T &target) { +void applyProperty(const ClassProperties &properties, PropertyKey key, T &target) { auto it = properties.properties.find(key); if (it != properties.properties.end()) { - const ClassPropertyValue &value = it->second; + const PropertyValue &value = it->second; if (value.is()) { target = value.get(); } @@ -70,10 +70,10 @@ void applyProperty(const ClassProperties &properties, ClassPropertyKey key, T &t } template -void applyProperty(const ClassProperties &properties, ClassPropertyKey key, T &target, float z) { +void applyProperty(const ClassProperties &properties, PropertyKey key, T &target, float z) { auto it = properties.properties.find(key); if (it != properties.properties.end()) { - const ClassPropertyValue &value = it->second; + const PropertyValue &value = it->second; if (value.is()) { target = value.get().evaluate(z); } else if (value.is()) { @@ -85,59 +85,59 @@ void applyProperty(const ClassProperties &properties, ClassPropertyKey key, T &t 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); + applyProperty(properties, PropertyKey::FillEnabled, fill.enabled, z); + applyProperty(properties, PropertyKey::FillAntialias, fill.antialias, z); + applyProperty(properties, PropertyKey::FillOpacity, fill.opacity, z); + applyProperty(properties, PropertyKey::FillColor, fill.fill_color); + applyProperty(properties, PropertyKey::FillOutlineColor, fill.stroke_color); + applyProperty(properties, PropertyKey::FillTranslateX, fill.translate[0], z); + applyProperty(properties, PropertyKey::FillTranslateY, fill.translate[1], z); + applyProperty(properties, PropertyKey::FillTranslateAnchor, fill.translateAnchor); + applyProperty(properties, PropertyKey::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); + applyProperty(properties, PropertyKey::LineEnabled, line.enabled, z); + applyProperty(properties, PropertyKey::LineOpacity, line.opacity, z); + applyProperty(properties, PropertyKey::LineColor, line.color); + applyProperty(properties, PropertyKey::LineTranslateX, line.translate[0], z); + applyProperty(properties, PropertyKey::LineTranslateY, line.translate[1], z); + applyProperty(properties, PropertyKey::LineTranslateAnchor, line.translateAnchor); + applyProperty(properties, PropertyKey::LineWidth, line.width, z); + applyProperty(properties, PropertyKey::LineOffset, line.offset, z); + applyProperty(properties, PropertyKey::LineBlur, line.blur, z); + applyProperty(properties, PropertyKey::LineDashLand, line.dash_array[0], z); + applyProperty(properties, PropertyKey::LineDashGap, line.dash_array[1], z); + applyProperty(properties, PropertyKey::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); + applyProperty(properties, PropertyKey::IconEnabled, icon.enabled, z); + applyProperty(properties, PropertyKey::IconOpacity, icon.opacity, z); + applyProperty(properties, PropertyKey::IconRotate, icon.rotate, z); + applyProperty(properties, PropertyKey::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); + applyProperty(properties, PropertyKey::TextEnabled, text.enabled, z); + applyProperty(properties, PropertyKey::TextOpacity, text.opacity, z); + applyProperty(properties, PropertyKey::TextSize, text.size, z); + applyProperty(properties, PropertyKey::TextColor, text.color); + applyProperty(properties, PropertyKey::TextHaloColor, text.halo_color); + applyProperty(properties, PropertyKey::TextHaloWidth, text.halo_width, z); + applyProperty(properties, PropertyKey::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); + applyProperty(properties, PropertyKey::CompositeEnabled, composite.enabled, z); + applyProperty(properties, PropertyKey::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); + applyProperty(properties, PropertyKey::RasterSpin, raster.spin, z); + applyProperty(properties, PropertyKey::RasterBrightnessLow, raster.brightness[0], z); + applyProperty(properties, PropertyKey::RasterBrightnessHigh, raster.brightness[1], z); + applyProperty(properties, PropertyKey::RasterSaturation, raster.saturation, z); + applyProperty(properties, PropertyKey::RasterContrast, raster.contrast, z); + applyProperty(properties, PropertyKey::RasterFade, raster.fade, z); } else if (style.is()) { BackgroundProperties &background = style.get(); - applyProperty(properties, ClassPropertyKey::BackgroundColor, background.color); + applyProperty(properties, PropertyKey::BackgroundColor, background.color); } } diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 1bbb4fd52..22d6d617c 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -172,7 +172,7 @@ void StyleParser::parseSources(JSVal value) { #pragma mark - Parse Style Properties -template<> bool StyleParser::parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { +template<> bool StyleParser::parseStyleProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value) { if (!value.HasMember(property_name)) { return false; } @@ -188,7 +188,7 @@ template<> bool StyleParser::parseStyleProperty(const char *property_name, } -template<> bool StyleParser::parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { +template<> bool StyleParser::parseStyleProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value) { if (!value.HasMember(property_name)) { return false; } @@ -203,7 +203,7 @@ template<> bool StyleParser::parseStyleProperty(const char *propert return true; } -template<> bool StyleParser::parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { +template<> bool StyleParser::parseStyleProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value) { if (!value.HasMember(property_name)) { return false; } @@ -219,7 +219,7 @@ template<> bool StyleParser::parseStyleProperty(const char } -template<> bool StyleParser::parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { +template<> bool StyleParser::parseStyleProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value) { if (!value.HasMember(property_name)) { return false; } @@ -234,7 +234,7 @@ template<> bool StyleParser::parseStyleProperty(const char *pr return true; } -template<> bool StyleParser::parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { +template<> bool StyleParser::parseStyleProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value) { if (!value.HasMember(property_name)) { return false; } @@ -257,7 +257,7 @@ template<> bool StyleParser::parseStyleProperty(const char *property_name return true; } -template <> bool StyleParser::parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { +template <> bool StyleParser::parseStyleProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value) { if (!value.HasMember(property_name)) { return false; } @@ -305,7 +305,7 @@ FunctionProperty::fn parseFunctionType(JSVal type) { } } -template<> bool StyleParser::parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { +template<> bool StyleParser::parseStyleProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value) { if (!value.HasMember(property_name)) { return false; } @@ -358,7 +358,7 @@ template<> bool StyleParser::parseStyleProperty(const char *pr } template -bool StyleParser::parseStyleProperty(const char *property_name, const std::vector &keys, ClassProperties &klass, JSVal value) { +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()) { @@ -478,7 +478,7 @@ void StyleParser::parseStyles(JSVal value, std::shared_ptr &layer) { } void StyleParser::parseStyle(JSVal value, ClassProperties &klass) { - using Key = ClassPropertyKey; + using Key = PropertyKey; parseStyleProperty("fill-enabled", Key::FillEnabled, klass, value); parseStyleProperty("fill-enabled-transition", Key::FillEnabled, klass, value); From e77b3d71c45cf2c1737dad1166695b11e00e3883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 27 Jun 2014 17:13:21 +0200 Subject: [PATCH 20/55] add raster enabled/opacity --- include/llmr/style/property_key.hpp | 2 ++ src/style/style.cpp | 2 ++ src/style/style_parser.cpp | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/include/llmr/style/property_key.hpp b/include/llmr/style/property_key.hpp index e35587239..47d0d2b78 100644 --- a/include/llmr/style/property_key.hpp +++ b/include/llmr/style/property_key.hpp @@ -46,6 +46,8 @@ enum class PropertyKey { CompositeEnabled, CompositeOpacity, + RasterEnabled, + RasterOpacity, RasterSpin, RasterBrightnessLow, RasterBrightnessHigh, diff --git a/src/style/style.cpp b/src/style/style.cpp index df14673f8..4f23cd5bb 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -129,6 +129,8 @@ void applyClassProperties(StyleProperties &style, const ClassProperties &propert applyProperty(properties, PropertyKey::CompositeOpacity, composite.opacity, z); } else if (style.is()) { RasterProperties &raster = style.get(); + applyProperty(properties, PropertyKey::RasterEnabled, raster.enabled, z); + applyProperty(properties, PropertyKey::RasterOpacity, raster.opacity, z); applyProperty(properties, PropertyKey::RasterSpin, raster.spin, z); applyProperty(properties, PropertyKey::RasterBrightnessLow, raster.brightness[0], z); applyProperty(properties, PropertyKey::RasterBrightnessHigh, raster.brightness[1], z); diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 22d6d617c..84ad6ada4 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -540,6 +540,10 @@ void StyleParser::parseStyle(JSVal value, ClassProperties &klass) { parseStyleProperty("composite-opacity", Key::CompositeOpacity, klass, value); parseStyleProperty("composite-opacity-transition", Key::CompositeOpacity, klass, value); + parseStyleProperty("raster-enabled", Key::RasterEnabled, klass, value); + parseStyleProperty("raster-enabled-transition", Key::RasterEnabled, klass, value); + parseStyleProperty("raster-opacity", Key::RasterOpacity, klass, value); + parseStyleProperty("raster-opacity-transition", Key::RasterOpacity, 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); From 4a9d12385b7b50e948b0b4870b5139e2c4fa60ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 27 Jun 2014 17:14:03 +0200 Subject: [PATCH 21/55] add remaining default values --- src/style/property_fallback.cpp | 43 +++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/style/property_fallback.cpp b/src/style/property_fallback.cpp index d322f8c57..d94f7e9e5 100644 --- a/src/style/property_fallback.cpp +++ b/src/style/property_fallback.cpp @@ -3,9 +3,52 @@ namespace llmr { const std::map PropertyFallbackValue::properties = { + { PropertyKey::FillEnabled, true }, + { PropertyKey::FillAntialias, true }, + { PropertyKey::FillOpacity, 1.0f }, + { PropertyKey::FillColor, Color({{ 0, 0, 0, 1 }}) }, + { PropertyKey::FillTranslateX, 0.0f }, + { PropertyKey::FillTranslateY, 0.0f }, + { PropertyKey::FillTranslateAnchor, TranslateAnchorType::Map }, + { PropertyKey::LineEnabled, true }, { PropertyKey::LineOpacity, 1.0f }, { PropertyKey::LineColor, Color({{ 0, 0, 0, 1 }}) }, + { PropertyKey::LineTranslateX, 0.0f }, + { PropertyKey::LineTranslateY, 0.0f }, + { PropertyKey::LineTranslateAnchor, TranslateAnchorType::Map }, + { PropertyKey::LineWidth, 1.0f }, + { PropertyKey::LineOffset, 0.0f }, + { PropertyKey::LineBlur, 1.0f }, + { PropertyKey::LineDashLand, 1.0f }, + { PropertyKey::LineDashGap, -1.0f }, + + { PropertyKey::IconEnabled, true }, + { PropertyKey::IconOpacity, 1.0f }, + { PropertyKey::IconRotate, 0.0f }, + { PropertyKey::IconRotateAnchor, RotateAnchorType::Viewport }, + + { PropertyKey::TextEnabled, true }, + { PropertyKey::TextOpacity, 1.0f }, + { PropertyKey::TextSize, 16.0f }, + { PropertyKey::TextColor, Color({{ 0, 0, 0, 1 }}) }, + { PropertyKey::TextHaloColor, Color({{ 0, 0, 0, 0 }}) }, + { PropertyKey::TextHaloWidth, 0.25f }, + { PropertyKey::TextHaloBlur, 1.0f }, + + { PropertyKey::CompositeEnabled, true }, + { PropertyKey::CompositeOpacity, 1.0f }, + + { PropertyKey::RasterEnabled, true }, + { PropertyKey::RasterOpacity, 1.0f }, + { PropertyKey::RasterSpin, 0.0f }, + { PropertyKey::RasterBrightnessLow, 0.0f }, + { PropertyKey::RasterBrightnessHigh, 1.0f }, + { PropertyKey::RasterSaturation, 0.0f }, + { PropertyKey::RasterContrast, 0.0f }, + { PropertyKey::RasterFade, 0.0f }, + + { PropertyKey::BackgroundColor, Color({{ 0, 0, 0, 0 }}) }, }; const PropertyValue PropertyFallbackValue::defaultProperty; From 9761140deb30ba0c960e62a2ef72665c2ee68f41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 27 Jun 2014 17:15:16 +0200 Subject: [PATCH 22/55] names are transiton-*, not *-transition --- src/style/style_parser.cpp | 64 +++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 84ad6ada4..28dfddad7 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -481,81 +481,81 @@ void StyleParser::parseStyle(JSVal value, ClassProperties &klass) { using Key = PropertyKey; parseStyleProperty("fill-enabled", Key::FillEnabled, klass, value); - parseStyleProperty("fill-enabled-transition", Key::FillEnabled, klass, value); + parseStyleProperty("transition-fill-enabled", 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("transition-fill-opacity", Key::FillOpacity, klass, value); parseStyleProperty("fill-color", Key::FillColor, klass, value); - parseStyleProperty("fill-color-transition", Key::FillColor, klass, value); + parseStyleProperty("transition-fill-color", Key::FillColor, klass, value); parseStyleProperty("fill-outline-color", Key::FillOutlineColor, klass, value); - parseStyleProperty("fill-outline-color-transition", Key::FillOutlineColor, klass, value); + parseStyleProperty("transition-fill-outline-color", Key::FillOutlineColor, klass, value); parseStyleProperty("fill-translate", { Key::FillTranslateX, Key::FillTranslateY }, klass, value); - parseStyleProperty("fill-translate-transition", Key::FillTranslate, klass, value); + parseStyleProperty("transition-fill-translate", 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("transition-line-enabled", Key::LineEnabled, klass, value); parseStyleProperty("line-opacity", Key::LineOpacity, klass, value); - parseStyleProperty("line-opacity-transition", Key::LineOpacity, klass, value); + parseStyleProperty("transition-line-opacity", Key::LineOpacity, klass, value); parseStyleProperty("line-color", Key::LineColor, klass, value); - parseStyleProperty("line-color-transition", Key::LineColor, klass, value); + parseStyleProperty("transition-line-color", Key::LineColor, klass, value); parseStyleProperty("line-translate", { Key::LineTranslateX, Key::LineTranslateY }, klass, value); - parseStyleProperty("line-translate-transition", Key::LineTranslate, klass, value); + parseStyleProperty("transition-line-translate", 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("transition-line-width", Key::LineWidth, klass, value); parseStyleProperty("line-offset", Key::LineOffset, klass, value); - parseStyleProperty("line-offset-transition", Key::LineOffset, klass, value); + parseStyleProperty("transition-line-offset", Key::LineOffset, klass, value); parseStyleProperty("line-blur", Key::LineBlur, klass, value); - parseStyleProperty("line-blur-transition", Key::LineBlur, klass, value); + parseStyleProperty("transition-line-blur", Key::LineBlur, klass, value); parseStyleProperty("line-dasharray", { Key::LineDashLand, Key::LineDashGap }, klass, value); - parseStyleProperty("line-dasharray-transition", Key::LineDashArray, klass, value); + parseStyleProperty("transition-line-dasharray", 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("transition-icon-enabled", Key::IconEnabled, klass, value); parseStyleProperty("icon-opacity", Key::IconOpacity, klass, value); - parseStyleProperty("icon-opacity-transition", Key::IconOpacity, klass, value); + parseStyleProperty("transition-icon-opacity", 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("transition-text-enabled", Key::TextEnabled, klass, value); parseStyleProperty("text-opacity", Key::TextOpacity, klass, value); - parseStyleProperty("text-opacity-transition", Key::TextOpacity, klass, value); + parseStyleProperty("transition-text-opacity", Key::TextOpacity, klass, value); parseStyleProperty("text-size", Key::TextSize, klass, value); - parseStyleProperty("text-size-transition", Key::TextSize, klass, value); + parseStyleProperty("transition-text-size", Key::TextSize, klass, value); parseStyleProperty("text-color", Key::TextColor, klass, value); - parseStyleProperty("text-color-transition", Key::TextColor, klass, value); + parseStyleProperty("transition-text-color", Key::TextColor, klass, value); parseStyleProperty("text-halo-color", Key::TextHaloColor, klass, value); - parseStyleProperty("text-halo-color-transition", Key::TextHaloColor, klass, value); + parseStyleProperty("transition-text-halo-color", Key::TextHaloColor, klass, value); parseStyleProperty("text-halo-width", Key::TextHaloWidth, klass, value); - parseStyleProperty("text-halo-width-transition", Key::TextHaloWidth, klass, value); + parseStyleProperty("transition-text-halo-width", Key::TextHaloWidth, klass, value); parseStyleProperty("text-halo-blur", Key::TextHaloBlur, klass, value); - parseStyleProperty("text-halo-blur-transition", Key::TextHaloBlur, klass, value); + parseStyleProperty("transition-text-halo-blur", Key::TextHaloBlur, klass, value); parseStyleProperty("composite-enabled", Key::CompositeEnabled, klass, value); - parseStyleProperty("composite-enabled-transition", Key::CompositeEnabled, klass, value); + parseStyleProperty("transition-composite-enabled", Key::CompositeEnabled, klass, value); parseStyleProperty("composite-opacity", Key::CompositeOpacity, klass, value); - parseStyleProperty("composite-opacity-transition", Key::CompositeOpacity, klass, value); + parseStyleProperty("transition-composite-opacity", Key::CompositeOpacity, klass, value); parseStyleProperty("raster-enabled", Key::RasterEnabled, klass, value); - parseStyleProperty("raster-enabled-transition", Key::RasterEnabled, klass, value); + parseStyleProperty("transition-raster-enabled", Key::RasterEnabled, klass, value); parseStyleProperty("raster-opacity", Key::RasterOpacity, klass, value); - parseStyleProperty("raster-opacity-transition", Key::RasterOpacity, klass, value); + parseStyleProperty("transition-raster-opacity", Key::RasterOpacity, klass, value); parseStyleProperty("raster-spin", Key::RasterSpin, klass, value); - parseStyleProperty("raster-spin-transition", Key::RasterSpin, klass, value); + parseStyleProperty("transition-raster-spin", Key::RasterSpin, klass, value); parseStyleProperty("raster-brightness-low", Key::RasterBrightnessLow, klass, value); - parseStyleProperty("raster-brightness-low-transition", Key::RasterBrightnessLow, klass, value); + parseStyleProperty("transition-raster-brightness-low", Key::RasterBrightnessLow, klass, value); parseStyleProperty("raster-brightness-high", Key::RasterBrightnessHigh, klass, value); - parseStyleProperty("raster-brightness-high-transition", Key::RasterBrightnessHigh, klass, value); + parseStyleProperty("transition-raster-brightness-high", Key::RasterBrightnessHigh, klass, value); parseStyleProperty("raster-saturation", Key::RasterSaturation, klass, value); - parseStyleProperty("raster-saturation-transition", Key::RasterSaturation, klass, value); + parseStyleProperty("transition-raster-saturation", Key::RasterSaturation, klass, value); parseStyleProperty("raster-contrast", Key::RasterContrast, klass, value); - parseStyleProperty("raster-contrast-transition", Key::RasterContrast, klass, value); + parseStyleProperty("transition-raster-contrast", Key::RasterContrast, klass, value); parseStyleProperty("raster-fade", Key::RasterFade, klass, value); - parseStyleProperty("raster-fade-transition", Key::RasterFade, klass, value); + parseStyleProperty("transition-raster-fade", Key::RasterFade, klass, value); parseStyleProperty("background-color", Key::BackgroundColor, klass, value); } From 881c0f14129038fa3dca762681426c695ed3e891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 27 Jun 2014 18:01:28 +0200 Subject: [PATCH 23/55] more docs + remove StyleLayer::Ptr typedef --- include/llmr/style/style_layer.hpp | 18 +++++++++++++++--- src/map/map.cpp | 4 ++-- src/style/style_parser.cpp | 4 ++-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/include/llmr/style/style_layer.hpp b/include/llmr/style/style_layer.hpp index 889cd8648..19490c928 100644 --- a/include/llmr/style/style_layer.hpp +++ b/include/llmr/style/style_layer.hpp @@ -19,9 +19,6 @@ class StyleLayer; typedef std::vector> StyleLayerGroup; class StyleLayer { -public: - typedef std::shared_ptr Ptr; - public: template const T &getProperties() { if (style.is()) { @@ -32,11 +29,26 @@ public: } public: + // The name of this layer. std::string id; + + // Bucket information, telling the renderer how to generate the geometries + // for this layer (feature property filters, tessellation instructions, ...). std::shared_ptr bucket; + + // Contains all style classes that can be applied to this layer. std::map styles; + + // Stores the evaluated, and cascaded styling information, specific to this + // layer's type. StyleProperties style; + + // Rasterization properties are used for prerendering the tile to a bitmap, + // which is then used as a raster image instead of rendering this layer + // directly in every frame. std::unique_ptr rasterize; + + // Child layer array (if this layer has child layers). std::shared_ptr layers; }; diff --git a/src/map/map.cpp b/src/map/map.cpp index 44c62eeb2..f0513ad32 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -533,7 +533,7 @@ void Map::renderLayers(std::shared_ptr layers) { if (debug::renderTree) { std::cout << std::string(indent++ * 4, ' ') << "OPAQUE {" << std::endl; } - typedef std::vector::reverse_iterator riterator; + typedef StyleLayerGroup::reverse_iterator riterator; int i = 0; for (riterator it = layers->rbegin(), end = layers->rend(); it != end; ++it, ++i) { painter.setOpaque(); @@ -550,7 +550,7 @@ void Map::renderLayers(std::shared_ptr layers) { if (debug::renderTree) { std::cout << std::string(indent++ * 4, ' ') << "TRANSLUCENT {" << std::endl; } - typedef std::vector::iterator iterator; + typedef StyleLayerGroup::iterator iterator; --i; for (iterator it = layers->begin(), end = layers->end(); it != end; ++it, --i) { painter.setTranslucent(); diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 28dfddad7..e3453107c 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -390,8 +390,8 @@ std::unique_ptr StyleParser::createLayers(JSVal value) { } } -StyleLayer::Ptr StyleParser::createLayer(JSVal value) { - StyleLayer::Ptr layer = std::make_shared(); +std::shared_ptr StyleParser::createLayer(JSVal value) { + std::shared_ptr layer = std::make_shared(); if (value.IsObject()) { if (!value.HasMember("id")) { From 48019ae85cb5369babefa7ff78376146f14987a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 27 Jun 2014 18:39:42 +0200 Subject: [PATCH 24/55] make more members of StyleLayer const --- include/llmr/style/style_layer.hpp | 13 ++++--- include/llmr/style/style_parser.hpp | 10 ++++-- src/map/tile_parser.cpp | 2 +- src/style/style_layer.cpp | 13 +++++++ src/style/style_parser.cpp | 55 +++++++++++++++++------------ 5 files changed, 64 insertions(+), 29 deletions(-) create mode 100644 src/style/style_layer.cpp diff --git a/include/llmr/style/style_layer.hpp b/include/llmr/style/style_layer.hpp index 19490c928..fe5d3c3a6 100644 --- a/include/llmr/style/style_layer.hpp +++ b/include/llmr/style/style_layer.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -13,13 +14,15 @@ namespace llmr { class StyleBucket; -class RasterizeProperties; class StyleLayer; typedef std::vector> StyleLayerGroup; class StyleLayer { public: + StyleLayer(const std::string &id, std::map &&styles, + std::unique_ptr &&rasterize); + template const T &getProperties() { if (style.is()) { return style.get(); @@ -28,16 +31,18 @@ public: } } + bool isBackground() const; + public: // The name of this layer. - std::string id; + const std::string id; // Bucket information, telling the renderer how to generate the geometries // for this layer (feature property filters, tessellation instructions, ...). std::shared_ptr bucket; // Contains all style classes that can be applied to this layer. - std::map styles; + const std::map styles; // Stores the evaluated, and cascaded styling information, specific to this // layer's type. @@ -46,7 +51,7 @@ public: // Rasterization properties are used for prerendering the tile to a bitmap, // which is then used as a raster image instead of rendering this layer // directly in every frame. - std::unique_ptr rasterize; + const std::unique_ptr rasterize; // Child layer array (if this layer has child layers). std::shared_ptr layers; diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 52866f771..808d3188d 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -14,6 +15,8 @@ namespace llmr { +enum class ClassID : uint32_t; + class StyleLayer; typedef std::vector> StyleLayerGroup; @@ -37,9 +40,9 @@ private: std::shared_ptr createLayer(JSVal value); void parseLayers(); void parseLayer(std::pair> &pair); - void parseStyles(JSVal value, std::shared_ptr &layer); + void parseStyles(JSVal value, std::map &styles); void parseStyle(JSVal, ClassProperties &properties); - void parseRasterize(JSVal value, std::shared_ptr &layer); + std::unique_ptr parseRasterize(JSVal value); void parseReference(JSVal value, std::shared_ptr &layer); void parseBucket(JSVal value, std::shared_ptr &layer); void parseRender(JSVal value, std::shared_ptr &layer); @@ -73,6 +76,9 @@ private: // This maps ids to Layer objects, with all items being at the root level. std::unordered_map>> layers; + // Layer IDs that we have encountered previously while parsing this stylesheet. + std::set existing_layer_ids; + // Store a stack of layers we're parsing right now. This is to prevent reference cycles. std::forward_list stack; }; diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 847c57d08..45fa02672 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -74,7 +74,7 @@ void TileParser::parseStyleLayers(std::shared_ptr layers) { return; } - if (layer_desc->id == "background") { + if (layer_desc->isBackground()) { // background is a special, fake bucket continue; } else if (layer_desc->layers) { diff --git a/src/style/style_layer.cpp b/src/style/style_layer.cpp new file mode 100644 index 000000000..f60f3f064 --- /dev/null +++ b/src/style/style_layer.cpp @@ -0,0 +1,13 @@ +#include + +namespace llmr { + +StyleLayer::StyleLayer(const std::string &id, std::map &&styles, + std::unique_ptr &&rasterize) + : id(id), styles(std::move(styles)), rasterize(std::move(rasterize)) {} + +bool StyleLayer::isBackground() const { + return id == "background"; +} + +} diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index e3453107c..4ecb9a0bc 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -382,7 +382,10 @@ 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])); + std::shared_ptr layer = createLayer(value[i]); + if (layer) { + layers->emplace_back(layer); + } } return layers; } else { @@ -391,43 +394,50 @@ std::unique_ptr StyleParser::createLayers(JSVal value) { } std::shared_ptr StyleParser::createLayer(JSVal value) { - std::shared_ptr layer = std::make_shared(); - if (value.IsObject()) { if (!value.HasMember("id")) { - throw Style::exception("layer must have an id"); + fprintf(stderr, "[WARNING] layer must have an id\n"); + return nullptr; } JSVal id = value["id"]; if (!id.IsString()) { - throw Style::exception("layer id must be a string"); + fprintf(stderr, "[WARNING] layer id must be a string\n"); + return nullptr; } - layer->id = { id.GetString(), id.GetStringLength() }; + const std::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()); + if (existing_layer_ids.find(layer_id) != existing_layer_ids.end()) { + fprintf(stderr, "[WARNING] duplicate layer id %s\n", layer_id.c_str()); + return nullptr; } - // 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 styles already, as they can't be inherited anyway. + std::map styles; + parseStyles(value, styles); // Parse Rasterization options, as they can't be inherited anyway. + std::unique_ptr rasterize; if (value.HasMember("rasterize")) { - parseRasterize(replaceConstant(value["rasterize"]), layer); + rasterize = parseRasterize(replaceConstant(value["rasterize"])); } + std::shared_ptr layer = std::make_shared( + layer_id, std::move(styles), std::move(rasterize)); + if (value.HasMember("layers")) { layer->layers = createLayers(value["layers"]); } - } else { - throw Style::exception("layer must be an object"); - } - return layer; + // Store the layer ID so we can reference it later. + layers.emplace(layer_id, std::pair> { value, layer }); + + return layer; + } else { + fprintf(stderr, "[WARNING] layer must be an object\n"); + return nullptr; + } } void StyleParser::parseLayers() { @@ -463,16 +473,16 @@ void StyleParser::parseLayer(std::pair> &pair #pragma mark - Parse Styles -void StyleParser::parseStyles(JSVal value, std::shared_ptr &layer) { +void StyleParser::parseStyles(JSVal value, std::map &styles) { 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[ClassID::Default]); + parseStyle(replaceConstant(itr->value), styles[ClassID::Default]); } else if (name.compare(0, 6, "style.") == 0 && name.length() > 6) { const ClassID class_id = ClassDictionary::Lookup(name.substr(6)); - parseStyle(replaceConstant(itr->value), layer->styles[class_id]); + parseStyle(replaceConstant(itr->value), styles[class_id]); } } } @@ -560,8 +570,9 @@ void StyleParser::parseStyle(JSVal value, ClassProperties &klass) { parseStyleProperty("background-color", Key::BackgroundColor, klass, value); } -void StyleParser::parseRasterize(JSVal value, std::shared_ptr &layer) { +std::unique_ptr StyleParser::parseRasterize(JSVal value) { // TODO + return nullptr; } void StyleParser::parseReference(JSVal value, std::shared_ptr &layer) { From a41f0db7dd81f4c9163965d252769cab7e430feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 27 Jun 2014 19:11:57 +0200 Subject: [PATCH 25/55] add way for adding/removing classes --- include/llmr/style/style_layer.hpp | 17 +++++++ src/style/style_layer.cpp | 78 ++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/include/llmr/style/style_layer.hpp b/include/llmr/style/style_layer.hpp index fe5d3c3a6..b45982b79 100644 --- a/include/llmr/style/style_layer.hpp +++ b/include/llmr/style/style_layer.hpp @@ -5,11 +5,13 @@ #include #include #include +#include #include #include #include #include +#include namespace llmr { @@ -33,6 +35,15 @@ public: bool isBackground() const; + // Sets the list of classes and creates transitions to the currently applied values. + void setClasses(const std::vector &class_names, timestamp now, + const ClassPropertyTransition &defaultTransition); + +private: + // Applies all properties from a class, if they haven't been applied already. + void applyClassProperties(ClassID class_id, std::set &already_applied, + timestamp now, const ClassPropertyTransition &defaultTransition); + public: // The name of this layer. const std::string id; @@ -44,6 +55,12 @@ public: // Contains all style classes that can be applied to this layer. const std::map styles; +private: + // For every property, stores a list of applied property values, with + // optional transition times. + std::map appliedStyle; + +public: // Stores the evaluated, and cascaded styling information, specific to this // layer's type. StyleProperties style; diff --git a/src/style/style_layer.cpp b/src/style/style_layer.cpp index f60f3f064..eccadbeed 100644 --- a/src/style/style_layer.cpp +++ b/src/style/style_layer.cpp @@ -1,4 +1,5 @@ #include +#include namespace llmr { @@ -10,4 +11,81 @@ bool StyleLayer::isBackground() const { return id == "background"; } +void StyleLayer::setClasses(const std::vector &class_names, const timestamp now, + const ClassPropertyTransition &defaultTransition) { + // Stores all keys that we have already added transitions for. + std::set already_applied; + + // Reverse iterate through all class names and apply them last to first. + for (auto it = class_names.rbegin(); it != class_names.rend(); it++) { + const std::string &class_name = *it; + // From here on, we're only dealing with IDs to avoid comparing strings all the time. + const ClassID class_id = ClassDictionary::Lookup(class_name); + applyClassProperties(class_id, already_applied, now, defaultTransition); + } + + // As the last class, apply the default class. + applyClassProperties(ClassID::Default, already_applied, now, defaultTransition); + + // Make sure that we also transition to the fallback value for keys that aren't changed by + // any applied classes. + for (std::pair &property_pair : appliedStyle) { + const PropertyKey key = property_pair.first; + if (already_applied.find(key) != already_applied.end()) { + // This property has already been set by a previous class, so we don't need to + // transition to the fallback. + continue; + } + + AppliedClassProperties &appliedProperties = property_pair.second; + // Make sure that we don't do double transitions to the fallback value. + if (appliedProperties.mostRecent() != ClassID::Fallback) { + // This property key hasn't been set by a previous class, so we need to add a transition + // to the fallback value for that key. + const timestamp begin = now + defaultTransition.delay; + const timestamp end = begin + defaultTransition.duration; + const PropertyValue &value = PropertyFallbackValue::Get(key); + appliedProperties.add(ClassID::Fallback, begin, end, value); + } + } +} + +// Helper function for applying all properties of a a single class that haven't been applied yet. +void StyleLayer::applyClassProperties(const ClassID class_id, + std::set &already_applied, timestamp now, + const ClassPropertyTransition &defaultTransition) { + auto style_it = styles.find(class_id); + if (style_it == styles.end()) { + // There is no class in this layer with this class_name. + return; + } + + // Loop through all the properties in this style, and add transitions to them, if they're + // not already the most recent transition. + const ClassProperties &properties = style_it->second; + for (const std::pair &property_pair : properties) { + PropertyKey key = property_pair.first; + if (already_applied.find(key) != already_applied.end()) { + // This property has already been set by a previous class. + continue; + } + + // Mark this property as written by a previous class, so that subsequent + // classes won't override this. + already_applied.insert(key); + + // If the most recent transition is not the one with the highest priority, create + // a transition. + AppliedClassProperties &appliedProperties = appliedStyle[key]; + if (appliedProperties.mostRecent() != class_id) { + const ClassPropertyTransition &transition = + properties.getTransition(key, defaultTransition); + const timestamp begin = now + transition.delay; + const timestamp end = begin + transition.duration; + const PropertyValue &value = property_pair.second; + appliedProperties.add(class_id, begin, end, value); + } + } +} + } From 8feedf7fc2f9b41a48d9f02ea572d312514f115f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 27 Jun 2014 19:15:33 +0200 Subject: [PATCH 26/55] also update child layers --- src/style/style_layer.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/style/style_layer.cpp b/src/style/style_layer.cpp index eccadbeed..9e6de7861 100644 --- a/src/style/style_layer.cpp +++ b/src/style/style_layer.cpp @@ -48,6 +48,15 @@ void StyleLayer::setClasses(const std::vector &class_names, const t appliedProperties.add(ClassID::Fallback, begin, end, value); } } + + // Update all child layers as well. + if (layers) { + for (std::shared_ptr &layer : *layers) { + if (layer) { + layer->setClasses(class_names, now, defaultTransition); + } + } + } } // Helper function for applying all properties of a a single class that haven't been applied yet. From 93cd4c5c7b0939038eab38a6f6eb71eae4014acb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 30 Jun 2014 11:46:03 +0200 Subject: [PATCH 27/55] move StyleLayerGroup and PropertyTransition to their own files --- include/llmr/map/map.hpp | 2 +- include/llmr/map/tile_parser.hpp | 4 +- .../llmr/style/applied_class_properties.hpp | 8 +- include/llmr/style/class_properties.hpp | 10 +-- include/llmr/style/property_transition.hpp | 15 ++++ include/llmr/style/style.hpp | 27 +++---- include/llmr/style/style_layer.hpp | 14 ++-- include/llmr/style/style_layer_group.hpp | 21 +++++ include/llmr/style/style_parser.hpp | 2 +- src/map/map.cpp | 31 ++------ src/map/tile_parser.cpp | 7 +- src/style/applied_class_properties.cpp | 11 +++ src/style/style.cpp | 50 +++++------- src/style/style_layer.cpp | 13 ++-- src/style/style_layer_group.cpp | 14 ++++ src/style/style_parser.cpp | 76 +++++++++---------- 16 files changed, 166 insertions(+), 139 deletions(-) create mode 100644 include/llmr/style/property_transition.hpp create mode 100644 include/llmr/style/style_layer_group.hpp create mode 100644 src/style/applied_class_properties.cpp create mode 100644 src/style/style_layer_group.cpp diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index 54cbdcb16..75090f941 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -132,7 +132,7 @@ private: // Unconditionally performs a render with the current map state. void render(); - void renderLayers(std::shared_ptr layers); + void renderLayers(std::shared_ptr group); void renderLayer(std::shared_ptr layer_desc, RenderPass pass); private: diff --git a/include/llmr/map/tile_parser.hpp b/include/llmr/map/tile_parser.hpp index c4fd3d8bc..e18c2746a 100644 --- a/include/llmr/map/tile_parser.hpp +++ b/include/llmr/map/tile_parser.hpp @@ -16,7 +16,7 @@ class GlyphStore; class SpriteAtlas; class VectorTileData; class StyleLayer; -typedef std::vector> StyleLayerGroup; +class StyleLayerGroup; class StyleBucket; class StyleBucketFill; class StyleBucketLine; @@ -38,7 +38,7 @@ public: private: bool obsolete() const; void parseGlyphs(); - void parseStyleLayers(std::shared_ptr layers); + void parseStyleLayers(std::shared_ptr group); void addGlyph(uint64_t tileid, const std::string stackname, const std::u32string &string, const FontStack &fontStack, GlyphAtlas &glyphAtlas, GlyphPositions &face); std::unique_ptr createBucket(std::shared_ptr bucket_desc); diff --git a/include/llmr/style/applied_class_properties.hpp b/include/llmr/style/applied_class_properties.hpp index f90102200..cda3a42a4 100644 --- a/include/llmr/style/applied_class_properties.hpp +++ b/include/llmr/style/applied_class_properties.hpp @@ -14,10 +14,10 @@ public: AppliedClassProperty(ClassID class_id, timestamp begin, timestamp end, const PropertyValue &value); public: - ClassID name; - timestamp begin; - timestamp end; - PropertyValue value; + const ClassID name; + const timestamp begin; + const timestamp end; + const PropertyValue value; }; diff --git a/include/llmr/style/class_properties.hpp b/include/llmr/style/class_properties.hpp index 79b16e51a..3755563fe 100644 --- a/include/llmr/style/class_properties.hpp +++ b/include/llmr/style/class_properties.hpp @@ -3,16 +3,12 @@ #include #include +#include #include namespace llmr { -struct ClassPropertyTransition { - uint16_t duration = 0; - uint16_t delay = 0; -}; - class ClassProperties { public: inline ClassProperties() {} @@ -28,7 +24,7 @@ public: transitions.emplace(::std::forward(args)...); } - inline const ClassPropertyTransition &getTransition(PropertyKey key, const ClassPropertyTransition &defaultTransition) const { + inline const PropertyTransition &getTransition(PropertyKey key, const PropertyTransition &defaultTransition) const { auto it = transitions.find(key); if (it == transitions.end()) { return defaultTransition; @@ -47,7 +43,7 @@ public: public: std::map properties; - std::map transitions; + std::map transitions; }; } diff --git a/include/llmr/style/property_transition.hpp b/include/llmr/style/property_transition.hpp new file mode 100644 index 000000000..017527443 --- /dev/null +++ b/include/llmr/style/property_transition.hpp @@ -0,0 +1,15 @@ +#ifndef LLMR_STYLE_PROPERTY_TRANSITION +#define LLMR_STYLE_PROPERTY_TRANSITION + +#include + +namespace llmr { + +struct PropertyTransition { + uint16_t duration = 0; + uint16_t delay = 0; +}; + +} + +#endif \ No newline at end of file diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index 383aa5d75..62864b75f 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -1,11 +1,12 @@ #ifndef LLMR_STYLE_STYLE #define LLMR_STYLE_STYLE -#include +#include #include #include +#include #include #include #include @@ -17,7 +18,7 @@ namespace llmr { class Sprite; class Source; class StyleLayer; -typedef std::vector> StyleLayerGroup; +class StyleLayerGroup; class Style { public: @@ -26,20 +27,13 @@ public: public: Style(); - void reset(); - void loadJSON(const uint8_t *const data); size_t layerCount() const; - void cascade(float z); + void updateProperties(float z, timestamp t); - bool needsTransition() const; - void updateTransitions(timestamp now); - void cancelTransitions(); + void setDefaultTransitionDuration(uint16_t duration_milliseconds = 0); - void setDefaultTransitionDuration(uint64_t duration_milliseconds = 0); - - void updateSources(); const std::set> getActiveSources() const; const std::vector &getAppliedClasses() const; @@ -51,14 +45,17 @@ public: std::shared_ptr background; std::vector appliedClasses; - private: - void updateSources(const std::shared_ptr &layers); - void cascade(const std::shared_ptr &layers, float z); + void updateSources(); + void updateSources(const std::shared_ptr &group); + + void updateProperties(const std::shared_ptr &group, float z, timestamp t); + + void updateClasses(); private: std::set> activeSources; - uint64_t default_transition_duration = 0; + PropertyTransition defaultTransition; bool initial_render_complete = false; mutable uv::rwlock mtx; diff --git a/include/llmr/style/style_layer.hpp b/include/llmr/style/style_layer.hpp index b45982b79..89d4e1476 100644 --- a/include/llmr/style/style_layer.hpp +++ b/include/llmr/style/style_layer.hpp @@ -16,9 +16,7 @@ namespace llmr { class StyleBucket; - -class StyleLayer; -typedef std::vector> StyleLayerGroup; +class StyleLayerGroup; class StyleLayer { public: @@ -33,16 +31,21 @@ public: } } + // Determines whether this layer is the background layer. bool isBackground() const; + // Updates the StyleProperties information in this layer by evaluating all + // pending transitions and applied classes in order. + void updateStyle(float z); + // Sets the list of classes and creates transitions to the currently applied values. void setClasses(const std::vector &class_names, timestamp now, - const ClassPropertyTransition &defaultTransition); + const PropertyTransition &defaultTransition); private: // Applies all properties from a class, if they haven't been applied already. void applyClassProperties(ClassID class_id, std::set &already_applied, - timestamp now, const ClassPropertyTransition &defaultTransition); + timestamp now, const PropertyTransition &defaultTransition); public: // The name of this layer. @@ -74,7 +77,6 @@ public: std::shared_ptr layers; }; - } #endif diff --git a/include/llmr/style/style_layer_group.hpp b/include/llmr/style/style_layer_group.hpp new file mode 100644 index 000000000..73214830f --- /dev/null +++ b/include/llmr/style/style_layer_group.hpp @@ -0,0 +1,21 @@ +#ifndef LLMR_STYLE_STYLE_LAYER_GROUP +#define LLMR_STYLE_STYLE_LAYER_GROUP + +#include + +#include + +namespace llmr { + +class StyleLayerGroup { +public: + void setClasses(const std::vector &class_names, timestamp now, + const PropertyTransition &defaultTransition); + +public: + std::vector> layers; +}; + +} + +#endif diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 808d3188d..3c2a12a2a 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -18,7 +18,7 @@ namespace llmr { enum class ClassID : uint32_t; class StyleLayer; -typedef std::vector> StyleLayerGroup; +class StyleLayerGroup; class StyleParser { public: diff --git a/src/map/map.cpp b/src/map/map.cpp index f0513ad32..3417f8f6b 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include @@ -176,7 +176,6 @@ void Map::setup() { void Map::setStyleJSON(std::string newStyleJSON) { styleJSON.swap(newStyleJSON); - style->cancelTransitions(); style->loadJSON((const uint8_t *)styleJSON.c_str()); update(); } @@ -384,14 +383,6 @@ void Map::toggleClass(const std::string &name) { style->toggleClass(name); } -//void Map::setAppliedClasses(const std::vector &appliedClasses) { -// style->cancelTransitions(); -// -// style->appliedClasses = appliedClasses; -// -// update(); -//} - const std::vector &Map::getAppliedClasses() const { return style->getAppliedClasses(); } @@ -448,14 +439,8 @@ void Map::prepare() { painter.clearFramebuffers(); } - style->cascade(state.getNormalizedZoom()); - - // Update style transitions. animationTime = util::now(); - if (style->needsTransition()) { - style->updateTransitions(animationTime); - update(); - } + style->updateProperties(state.getNormalizedZoom(), animationTime); // Allow the sprite atlas to potentially pull new sprite images if needed. if (style->sprite && style->sprite->isLoaded()) { @@ -517,14 +502,14 @@ void Map::render() { glFlush(); } -void Map::renderLayers(std::shared_ptr layers) { - if (!layers) { +void Map::renderLayers(std::shared_ptr group) { + if (!group) { // 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 / (group->layers.size() + 1); // - FIRST PASS ------------------------------------------------------------ // Render everything top-to-bottom by using reverse iterators. Render opaque @@ -533,9 +518,8 @@ void Map::renderLayers(std::shared_ptr layers) { if (debug::renderTree) { std::cout << std::string(indent++ * 4, ' ') << "OPAQUE {" << std::endl; } - typedef StyleLayerGroup::reverse_iterator riterator; int i = 0; - for (riterator it = layers->rbegin(), end = layers->rend(); it != end; ++it, ++i) { + for (auto it = group->layers.rbegin(), end = group->layers.rend(); it != end; ++it, ++i) { painter.setOpaque(); painter.setStrata(i * strata_thickness); renderLayer(*it, Opaque); @@ -550,9 +534,8 @@ void Map::renderLayers(std::shared_ptr layers) { if (debug::renderTree) { std::cout << std::string(indent++ * 4, ' ') << "TRANSLUCENT {" << std::endl; } - typedef StyleLayerGroup::iterator iterator; --i; - for (iterator it = layers->begin(), end = layers->end(); it != end; ++it, --i) { + for (auto it = group->layers.begin(), end = group->layers.end(); it != end; ++it, --i) { painter.setTranslucent(); painter.setStrata(i * strata_thickness); renderLayer(*it, Translucent); diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 45fa02672..b3a018f42 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -63,12 +64,12 @@ void TileParser::addGlyph(uint64_t tileid, const std::string stackname, } } -void TileParser::parseStyleLayers(std::shared_ptr layers) { - if (!layers) { +void TileParser::parseStyleLayers(std::shared_ptr group) { + if (!group) { return; } - for (const std::shared_ptr &layer_desc : *layers) { + for (const std::shared_ptr &layer_desc : group->layers) { // Cancel early when parsing. if (obsolete()) { return; diff --git a/src/style/applied_class_properties.cpp b/src/style/applied_class_properties.cpp new file mode 100644 index 000000000..0b191364d --- /dev/null +++ b/src/style/applied_class_properties.cpp @@ -0,0 +1,11 @@ +#include + +namespace llmr { + +AppliedClassProperty::AppliedClassProperty(ClassID class_id, timestamp begin, timestamp end, const PropertyValue &value) + : name(class_id), + begin(begin), + end(end), + value(value) {} + +} diff --git a/src/style/style.cpp b/src/style/style.cpp index 4f23cd5bb..c2794fed8 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -13,9 +13,6 @@ namespace llmr { Style::Style() { } -void Style::reset() { -} - void Style::updateSources() { activeSources.clear(); updateSources(layers); @@ -25,11 +22,11 @@ const std::set> Style::getActiveSources() const { return activeSources; } -void Style::updateSources(const std::shared_ptr &layers) { - if (!layers) { +void Style::updateSources(const std::shared_ptr &group) { + if (!group) { return; } - for (const std::shared_ptr &layer : *layers) { + for (const std::shared_ptr &layer : group->layers) { if (!layer) continue; if (layer->bucket) { if (layer->bucket->source) { @@ -143,16 +140,16 @@ void applyClassProperties(StyleProperties &style, const ClassProperties &propert } } -void Style::cascade(const std::shared_ptr &layers, float z) { - if (!layers) { +void Style::updateProperties(const std::shared_ptr &group, float z, timestamp t) { + if (!group) { return; } - for (const std::shared_ptr &layer : *layers) { + for (const std::shared_ptr &layer : group->layers) { if (!layer) continue; if (layer->layers) { - cascade(layer->layers, z); + updateProperties(layer->layers, z, t); } // Accomodate for different tile size. @@ -183,13 +180,12 @@ void Style::cascade(const std::shared_ptr &layers, float z) { } } -void Style::cascade(float z) { +void Style::updateProperties(float z, timestamp t) { uv::writelock lock(mtx); updateSources(); - reset(); - cascade(layers, z); + updateProperties(layers, z, t); // Apply transitions after the first time. if (!initial_render_complete) { @@ -198,22 +194,8 @@ void Style::cascade(float z) { } } -bool Style::needsTransition() const { - uv::readlock lock(mtx); - - return false; -} - -void Style::updateTransitions(timestamp now) { - uv::writelock lock(mtx); -} - -void Style::cancelTransitions() { - uv::writelock lock(mtx); -} - -void Style::setDefaultTransitionDuration(uint64_t duration_milliseconds) { - default_transition_duration = duration_milliseconds; +void Style::setDefaultTransitionDuration(uint16_t duration_milliseconds) { + defaultTransition.duration = duration_milliseconds; } const std::vector &Style::getAppliedClasses() const { @@ -229,6 +211,14 @@ void Style::toggleClass(const std::string &name) { appliedClasses.erase(it); } } + + updateClasses(); +} + +void Style::updateClasses() { + if (layers) { + layers->setClasses(appliedClasses, util::now(), defaultTransition); + } } void Style::loadJSON(const uint8_t *const data) { diff --git a/src/style/style_layer.cpp b/src/style/style_layer.cpp index 9e6de7861..3bfd23579 100644 --- a/src/style/style_layer.cpp +++ b/src/style/style_layer.cpp @@ -1,4 +1,5 @@ #include +#include #include namespace llmr { @@ -12,7 +13,7 @@ bool StyleLayer::isBackground() const { } void StyleLayer::setClasses(const std::vector &class_names, const timestamp now, - const ClassPropertyTransition &defaultTransition) { + const PropertyTransition &defaultTransition) { // Stores all keys that we have already added transitions for. std::set already_applied; @@ -51,18 +52,14 @@ void StyleLayer::setClasses(const std::vector &class_names, const t // Update all child layers as well. if (layers) { - for (std::shared_ptr &layer : *layers) { - if (layer) { - layer->setClasses(class_names, now, defaultTransition); - } - } + layers->setClasses(class_names, now, defaultTransition); } } // Helper function for applying all properties of a a single class that haven't been applied yet. void StyleLayer::applyClassProperties(const ClassID class_id, std::set &already_applied, timestamp now, - const ClassPropertyTransition &defaultTransition) { + const PropertyTransition &defaultTransition) { auto style_it = styles.find(class_id); if (style_it == styles.end()) { // There is no class in this layer with this class_name. @@ -87,7 +84,7 @@ void StyleLayer::applyClassProperties(const ClassID class_id, // a transition. AppliedClassProperties &appliedProperties = appliedStyle[key]; if (appliedProperties.mostRecent() != class_id) { - const ClassPropertyTransition &transition = + const PropertyTransition &transition = properties.getTransition(key, defaultTransition); const timestamp begin = now + transition.delay; const timestamp end = begin + transition.duration; diff --git a/src/style/style_layer_group.cpp b/src/style/style_layer_group.cpp new file mode 100644 index 000000000..2f0fdf39e --- /dev/null +++ b/src/style/style_layer_group.cpp @@ -0,0 +1,14 @@ +#include + +namespace llmr { + +void StyleLayerGroup::setClasses(const std::vector &class_names, timestamp now, + const PropertyTransition &defaultTransition) { + for (const std::shared_ptr &layer : layers) { + if (layer) { + layer->setClasses(class_names, now, defaultTransition); + } + } +} + +} diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 4ecb9a0bc..7fa23cc91 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -257,12 +257,12 @@ template<> bool StyleParser::parseStyleProperty(const char *property_name return true; } -template <> bool StyleParser::parseStyleProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value) { +template <> bool StyleParser::parseStyleProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value) { if (!value.HasMember(property_name)) { return false; } JSVal elements = replaceConstant(value[property_name]); - ClassPropertyTransition transition; + PropertyTransition transition; if (elements.IsObject()) { if (elements.HasMember("duration") && elements["duration"].IsNumber()) { @@ -380,14 +380,14 @@ bool StyleParser::parseStyleProperty(const char *property_name, const std::vecto std::unique_ptr StyleParser::createLayers(JSVal value) { if (value.IsArray()) { - std::unique_ptr layers = std::make_unique(); + std::unique_ptr group = std::make_unique(); for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { std::shared_ptr layer = createLayer(value[i]); if (layer) { - layers->emplace_back(layer); + group->layers.emplace_back(layer); } } - return layers; + return group; } else { throw Style::exception("layers must be an array"); } @@ -491,81 +491,81 @@ void StyleParser::parseStyle(JSVal value, ClassProperties &klass) { using Key = PropertyKey; parseStyleProperty("fill-enabled", Key::FillEnabled, klass, value); - parseStyleProperty("transition-fill-enabled", Key::FillEnabled, klass, value); + parseStyleProperty("transition-fill-enabled", Key::FillEnabled, klass, value); parseStyleProperty("fill-antialias", Key::FillAntialias, klass, value); parseStyleProperty("fill-opacity", Key::FillOpacity, klass, value); - parseStyleProperty("transition-fill-opacity", Key::FillOpacity, klass, value); + parseStyleProperty("transition-fill-opacity", Key::FillOpacity, klass, value); parseStyleProperty("fill-color", Key::FillColor, klass, value); - parseStyleProperty("transition-fill-color", Key::FillColor, klass, value); + parseStyleProperty("transition-fill-color", Key::FillColor, klass, value); parseStyleProperty("fill-outline-color", Key::FillOutlineColor, klass, value); - parseStyleProperty("transition-fill-outline-color", Key::FillOutlineColor, klass, value); + parseStyleProperty("transition-fill-outline-color", Key::FillOutlineColor, klass, value); parseStyleProperty("fill-translate", { Key::FillTranslateX, Key::FillTranslateY }, klass, value); - parseStyleProperty("transition-fill-translate", Key::FillTranslate, klass, value); + parseStyleProperty("transition-fill-translate", 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("transition-line-enabled", Key::LineEnabled, klass, value); + parseStyleProperty("transition-line-enabled", Key::LineEnabled, klass, value); parseStyleProperty("line-opacity", Key::LineOpacity, klass, value); - parseStyleProperty("transition-line-opacity", Key::LineOpacity, klass, value); + parseStyleProperty("transition-line-opacity", Key::LineOpacity, klass, value); parseStyleProperty("line-color", Key::LineColor, klass, value); - parseStyleProperty("transition-line-color", Key::LineColor, klass, value); + parseStyleProperty("transition-line-color", Key::LineColor, klass, value); parseStyleProperty("line-translate", { Key::LineTranslateX, Key::LineTranslateY }, klass, value); - parseStyleProperty("transition-line-translate", Key::LineTranslate, klass, value); + parseStyleProperty("transition-line-translate", Key::LineTranslate, klass, value); parseStyleProperty("line-translate-anchor", Key::LineTranslateAnchor, klass, value); parseStyleProperty("line-width", Key::LineWidth, klass, value); - parseStyleProperty("transition-line-width", Key::LineWidth, klass, value); + parseStyleProperty("transition-line-width", Key::LineWidth, klass, value); parseStyleProperty("line-offset", Key::LineOffset, klass, value); - parseStyleProperty("transition-line-offset", Key::LineOffset, klass, value); + parseStyleProperty("transition-line-offset", Key::LineOffset, klass, value); parseStyleProperty("line-blur", Key::LineBlur, klass, value); - parseStyleProperty("transition-line-blur", Key::LineBlur, klass, value); + parseStyleProperty("transition-line-blur", Key::LineBlur, klass, value); parseStyleProperty("line-dasharray", { Key::LineDashLand, Key::LineDashGap }, klass, value); - parseStyleProperty("transition-line-dasharray", Key::LineDashArray, klass, value); + parseStyleProperty("transition-line-dasharray", Key::LineDashArray, klass, value); parseStyleProperty("line-image", Key::LineImage, klass, value); parseStyleProperty("icon-enabled", Key::IconEnabled, klass, value); - parseStyleProperty("transition-icon-enabled", Key::IconEnabled, klass, value); + parseStyleProperty("transition-icon-enabled", Key::IconEnabled, klass, value); parseStyleProperty("icon-opacity", Key::IconOpacity, klass, value); - parseStyleProperty("transition-icon-opacity", Key::IconOpacity, klass, value); + parseStyleProperty("transition-icon-opacity", 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("transition-text-enabled", Key::TextEnabled, klass, value); + parseStyleProperty("transition-text-enabled", Key::TextEnabled, klass, value); parseStyleProperty("text-opacity", Key::TextOpacity, klass, value); - parseStyleProperty("transition-text-opacity", Key::TextOpacity, klass, value); + parseStyleProperty("transition-text-opacity", Key::TextOpacity, klass, value); parseStyleProperty("text-size", Key::TextSize, klass, value); - parseStyleProperty("transition-text-size", Key::TextSize, klass, value); + parseStyleProperty("transition-text-size", Key::TextSize, klass, value); parseStyleProperty("text-color", Key::TextColor, klass, value); - parseStyleProperty("transition-text-color", Key::TextColor, klass, value); + parseStyleProperty("transition-text-color", Key::TextColor, klass, value); parseStyleProperty("text-halo-color", Key::TextHaloColor, klass, value); - parseStyleProperty("transition-text-halo-color", Key::TextHaloColor, klass, value); + parseStyleProperty("transition-text-halo-color", Key::TextHaloColor, klass, value); parseStyleProperty("text-halo-width", Key::TextHaloWidth, klass, value); - parseStyleProperty("transition-text-halo-width", Key::TextHaloWidth, klass, value); + parseStyleProperty("transition-text-halo-width", Key::TextHaloWidth, klass, value); parseStyleProperty("text-halo-blur", Key::TextHaloBlur, klass, value); - parseStyleProperty("transition-text-halo-blur", Key::TextHaloBlur, klass, value); + parseStyleProperty("transition-text-halo-blur", Key::TextHaloBlur, klass, value); parseStyleProperty("composite-enabled", Key::CompositeEnabled, klass, value); - parseStyleProperty("transition-composite-enabled", Key::CompositeEnabled, klass, value); + parseStyleProperty("transition-composite-enabled", Key::CompositeEnabled, klass, value); parseStyleProperty("composite-opacity", Key::CompositeOpacity, klass, value); - parseStyleProperty("transition-composite-opacity", Key::CompositeOpacity, klass, value); + parseStyleProperty("transition-composite-opacity", Key::CompositeOpacity, klass, value); parseStyleProperty("raster-enabled", Key::RasterEnabled, klass, value); - parseStyleProperty("transition-raster-enabled", Key::RasterEnabled, klass, value); + parseStyleProperty("transition-raster-enabled", Key::RasterEnabled, klass, value); parseStyleProperty("raster-opacity", Key::RasterOpacity, klass, value); - parseStyleProperty("transition-raster-opacity", Key::RasterOpacity, klass, value); + parseStyleProperty("transition-raster-opacity", Key::RasterOpacity, klass, value); parseStyleProperty("raster-spin", Key::RasterSpin, klass, value); - parseStyleProperty("transition-raster-spin", Key::RasterSpin, klass, value); + parseStyleProperty("transition-raster-spin", Key::RasterSpin, klass, value); parseStyleProperty("raster-brightness-low", Key::RasterBrightnessLow, klass, value); - parseStyleProperty("transition-raster-brightness-low", Key::RasterBrightnessLow, klass, value); + parseStyleProperty("transition-raster-brightness-low", Key::RasterBrightnessLow, klass, value); parseStyleProperty("raster-brightness-high", Key::RasterBrightnessHigh, klass, value); - parseStyleProperty("transition-raster-brightness-high", Key::RasterBrightnessHigh, klass, value); + parseStyleProperty("transition-raster-brightness-high", Key::RasterBrightnessHigh, klass, value); parseStyleProperty("raster-saturation", Key::RasterSaturation, klass, value); - parseStyleProperty("transition-raster-saturation", Key::RasterSaturation, klass, value); + parseStyleProperty("transition-raster-saturation", Key::RasterSaturation, klass, value); parseStyleProperty("raster-contrast", Key::RasterContrast, klass, value); - parseStyleProperty("transition-raster-contrast", Key::RasterContrast, klass, value); + parseStyleProperty("transition-raster-contrast", Key::RasterContrast, klass, value); parseStyleProperty("raster-fade", Key::RasterFade, klass, value); - parseStyleProperty("transition-raster-fade", Key::RasterFade, klass, value); + parseStyleProperty("transition-raster-fade", Key::RasterFade, klass, value); parseStyleProperty("background-color", Key::BackgroundColor, klass, value); } From 18d898fae70681fba8cc31d73b581c360557746c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 30 Jun 2014 16:52:39 +0200 Subject: [PATCH 28/55] refactor functions --- bin/style.js | 42 ++- include/llmr/style/function_properties.hpp | 77 +++-- include/llmr/style/property_value.hpp | 11 +- include/llmr/style/rasterize_properties.hpp | 8 +- include/llmr/style/style.hpp | 7 +- include/llmr/style/style_layer.hpp | 13 +- include/llmr/style/style_layer_group.hpp | 1 + include/llmr/style/style_parser.hpp | 5 + src/style/function_properties.cpp | 151 +++++--- src/style/property_fallback.cpp | 2 +- src/style/style.cpp | 148 +------- src/style/style_layer.cpp | 175 ++++++++++ src/style/style_layer_group.cpp | 8 + src/style/style_parser.cpp | 363 ++++++++++++-------- 14 files changed, 615 insertions(+), 396 deletions(-) diff --git a/bin/style.js b/bin/style.js index 7ca40b612..691c91351 100644 --- a/bin/style.js +++ b/bin/style.js @@ -6,7 +6,7 @@ module.exports = { "@land": "#eee", "@water": "#999", "@park": "#bda", - "@road": "#fefefe", + "@road": "#FF00FF", "@border": "#6d90ab", "@building": "#ddd", "@building_outline": "#ccc", @@ -53,28 +53,26 @@ module.exports = { "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 - } + "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, + "max": 1000 } - }] + } }, { "id": "building", "source": "mapbox.mapbox-streets-v5", diff --git a/include/llmr/style/function_properties.hpp b/include/llmr/style/function_properties.hpp index 970d617d0..d1e1a5b1c 100644 --- a/include/llmr/style/function_properties.hpp +++ b/include/llmr/style/function_properties.hpp @@ -1,43 +1,72 @@ #ifndef LLMR_STYLE_FUNCTION_PROPERTIES #define LLMR_STYLE_FUNCTION_PROPERTIES +#include + #include namespace llmr { -namespace functions { +template +struct ConstantFunction { + inline ConstantFunction(const T &value) : value(value) {} + inline T evaluate(float) const { return value; } -float null(float z, const std::vector&); -float constant(float z, const std::vector& values); -float min(float z, const std::vector& values); -float max(float z, const std::vector& values); -float stops(float z, const std::vector& values); -float linear(float z, const std::vector& values); -float exponential(float z, const std::vector& values); +private: + const T value; +}; -} +template +struct LinearFunction { + inline LinearFunction(const T &value, float z_base, float slope, const T &min, const T &max) + : value(value), min(min), max(max), z_base(z_base), slope(slope) {} + T evaluate(float z) const; -struct FunctionProperty { - typedef float (*fn)(float z, const std::vector& values); +private: + const T value, min, max; + const float z_base, slope; +}; - fn function; - std::vector values; +template +struct ExponentialFunction { + inline ExponentialFunction(const T &value, float z_base, float slope, const T &min, + const T &max) + : value(value), min(min), max(max), z_base(z_base), slope(slope) {} + T evaluate(float z) const; - inline FunctionProperty() : function(&functions::null) {} +private: + const T value, min, max; + const float z_base, slope; +}; - inline FunctionProperty(const FunctionProperty &property) - : function(property.function), values(property.values) {} - inline FunctionProperty(FunctionProperty &&property) - : function(property.function), values(std::move(property.values)) {} +template +struct StopsFunction { + inline StopsFunction(const std::vector> &values) : values(values) {} + T evaluate(float z) const; +private: + const std::vector> values; +}; - inline void operator=(const FunctionProperty &rhs) { - function = rhs.function; - values = rhs.values; +template +using Function = util::variant< + ConstantFunction, + LinearFunction, + ExponentialFunction, + StopsFunction +>; + +template +struct FunctionEvaluator { + typedef T result_type; + inline FunctionEvaluator(float z) : z(z) {} + + template