summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/csscolorparser/csscolorparser.cpp6
-rw-r--r--src/mbgl/algorithm/generate_clip_ids.cpp1
-rw-r--r--src/mbgl/algorithm/update_renderables.hpp64
-rw-r--r--src/mbgl/annotation/annotation_manager.cpp94
-rw-r--r--src/mbgl/annotation/annotation_manager.hpp25
-rw-r--r--src/mbgl/annotation/annotation_source.cpp30
-rw-r--r--src/mbgl/annotation/annotation_source.hpp28
-rw-r--r--src/mbgl/annotation/annotation_tile.cpp39
-rw-r--r--src/mbgl/annotation/annotation_tile.hpp46
-rw-r--r--src/mbgl/annotation/fill_annotation_impl.cpp9
-rw-r--r--src/mbgl/annotation/fill_annotation_impl.hpp2
-rw-r--r--src/mbgl/annotation/line_annotation_impl.cpp8
-rw-r--r--src/mbgl/annotation/line_annotation_impl.hpp2
-rw-r--r--src/mbgl/annotation/shape_annotation_impl.cpp110
-rw-r--r--src/mbgl/annotation/shape_annotation_impl.hpp36
-rw-r--r--src/mbgl/annotation/style_sourced_annotation_impl.cpp13
-rw-r--r--src/mbgl/annotation/style_sourced_annotation_impl.hpp2
-rw-r--r--src/mbgl/annotation/symbol_annotation_impl.cpp5
-rw-r--r--src/mbgl/annotation/symbol_annotation_impl.hpp4
-rw-r--r--src/mbgl/geometry/buffer.hpp8
-rw-r--r--src/mbgl/geometry/circle_buffer.cpp4
-rw-r--r--src/mbgl/geometry/debug_font_buffer.cpp4
-rw-r--r--src/mbgl/geometry/elements_buffer.cpp4
-rw-r--r--src/mbgl/geometry/feature_index.cpp10
-rw-r--r--src/mbgl/geometry/feature_index.hpp10
-rw-r--r--src/mbgl/geometry/fill_buffer.cpp4
-rw-r--r--src/mbgl/geometry/glyph_atlas.cpp27
-rw-r--r--src/mbgl/geometry/glyph_atlas.hpp16
-rw-r--r--src/mbgl/geometry/icon_buffer.cpp3
-rw-r--r--src/mbgl/geometry/icon_buffer.hpp2
-rw-r--r--src/mbgl/geometry/line_atlas.cpp35
-rw-r--r--src/mbgl/geometry/line_atlas.hpp12
-rw-r--r--src/mbgl/geometry/line_buffer.cpp4
-rw-r--r--src/mbgl/geometry/static_vertex_buffer.cpp18
-rw-r--r--src/mbgl/geometry/static_vertex_buffer.hpp17
-rw-r--r--src/mbgl/geometry/text_buffer.cpp3
-rw-r--r--src/mbgl/geometry/text_buffer.hpp2
-rw-r--r--src/mbgl/geometry/vao.cpp5
-rw-r--r--src/mbgl/geometry/vao.hpp14
-rw-r--r--src/mbgl/gl/gl.cpp4
-rw-r--r--src/mbgl/gl/gl_config.cpp4
-rw-r--r--src/mbgl/gl/gl_config.hpp18
-rw-r--r--src/mbgl/gl/object_store.cpp23
-rw-r--r--src/mbgl/gl/object_store.hpp36
-rw-r--r--src/mbgl/gl/texture_pool.cpp75
-rw-r--r--src/mbgl/gl/texture_pool.hpp38
-rw-r--r--src/mbgl/map/camera.cpp1
-rw-r--r--src/mbgl/map/map.cpp56
-rw-r--r--src/mbgl/map/transform.cpp74
-rw-r--r--src/mbgl/map/transform.hpp6
-rw-r--r--src/mbgl/map/transform_state.cpp10
-rw-r--r--src/mbgl/map/transform_state.hpp7
-rw-r--r--src/mbgl/platform/event.cpp34
-rw-r--r--src/mbgl/platform/log.cpp11
-rw-r--r--src/mbgl/renderer/bucket.hpp23
-rw-r--r--src/mbgl/renderer/circle_bucket.cpp10
-rw-r--r--src/mbgl/renderer/circle_bucket.hpp6
-rw-r--r--src/mbgl/renderer/debug_bucket.cpp4
-rw-r--r--src/mbgl/renderer/debug_bucket.hpp4
-rw-r--r--src/mbgl/renderer/fill_bucket.cpp37
-rw-r--r--src/mbgl/renderer/fill_bucket.hpp18
-rw-r--r--src/mbgl/renderer/frame_history.cpp22
-rw-r--r--src/mbgl/renderer/frame_history.hpp8
-rw-r--r--src/mbgl/renderer/line_bucket.cpp22
-rw-r--r--src/mbgl/renderer/line_bucket.hpp14
-rw-r--r--src/mbgl/renderer/paint_parameters.hpp12
-rw-r--r--src/mbgl/renderer/painter.cpp151
-rw-r--r--src/mbgl/renderer/painter.hpp133
-rw-r--r--src/mbgl/renderer/painter_background.cpp103
-rw-r--r--src/mbgl/renderer/painter_circle.cpp58
-rw-r--r--src/mbgl/renderer/painter_clipping.cpp18
-rw-r--r--src/mbgl/renderer/painter_debug.cpp59
-rw-r--r--src/mbgl/renderer/painter_fill.cpp240
-rw-r--r--src/mbgl/renderer/painter_line.cpp173
-rw-r--r--src/mbgl/renderer/painter_raster.cpp44
-rw-r--r--src/mbgl/renderer/painter_symbol.cpp154
-rw-r--r--src/mbgl/renderer/raster_bucket.cpp27
-rw-r--r--src/mbgl/renderer/raster_bucket.hpp11
-rw-r--r--src/mbgl/renderer/render_item.hpp10
-rw-r--r--src/mbgl/renderer/render_pass.hpp10
-rw-r--r--src/mbgl/renderer/render_tile.cpp34
-rw-r--r--src/mbgl/renderer/render_tile.hpp34
-rw-r--r--src/mbgl/renderer/symbol_bucket.cpp61
-rw-r--r--src/mbgl/renderer/symbol_bucket.hpp20
-rw-r--r--src/mbgl/shader/circle_shader.cpp13
-rw-r--r--src/mbgl/shader/circle_shader.hpp6
-rw-r--r--src/mbgl/shader/collision_box_shader.cpp14
-rw-r--r--src/mbgl/shader/collision_box_shader.hpp4
-rw-r--r--src/mbgl/shader/icon_shader.cpp16
-rw-r--r--src/mbgl/shader/icon_shader.hpp9
-rw-r--r--src/mbgl/shader/line_shader.cpp14
-rw-r--r--src/mbgl/shader/line_shader.hpp8
-rw-r--r--src/mbgl/shader/linepattern_shader.cpp14
-rw-r--r--src/mbgl/shader/linepattern_shader.hpp6
-rw-r--r--src/mbgl/shader/linesdf_shader.cpp14
-rw-r--r--src/mbgl/shader/linesdf_shader.hpp8
-rw-r--r--src/mbgl/shader/outline_shader.cpp13
-rw-r--r--src/mbgl/shader/outline_shader.hpp5
-rw-r--r--src/mbgl/shader/outlinepattern_shader.cpp17
-rw-r--r--src/mbgl/shader/outlinepattern_shader.hpp31
-rw-r--r--src/mbgl/shader/pattern_shader.cpp17
-rw-r--r--src/mbgl/shader/pattern_shader.hpp29
-rw-r--r--src/mbgl/shader/plain_shader.cpp13
-rw-r--r--src/mbgl/shader/plain_shader.hpp5
-rw-r--r--src/mbgl/shader/raster_shader.cpp20
-rw-r--r--src/mbgl/shader/raster_shader.hpp12
-rw-r--r--src/mbgl/shader/sdf_shader.cpp32
-rw-r--r--src/mbgl/shader/sdf_shader.hpp26
-rw-r--r--src/mbgl/shader/shader.cpp61
-rw-r--r--src/mbgl/shader/shader.hpp26
-rw-r--r--src/mbgl/shader/shaders.hpp59
-rw-r--r--src/mbgl/shader/uniform.cpp7
-rw-r--r--src/mbgl/sprite/sprite_atlas.cpp28
-rw-r--r--src/mbgl/sprite/sprite_atlas.hpp38
-rw-r--r--src/mbgl/sprite/sprite_parser.cpp6
-rw-r--r--src/mbgl/storage/network_status.cpp2
-rw-r--r--src/mbgl/storage/resource.cpp40
-rw-r--r--src/mbgl/storage/response.cpp6
-rw-r--r--src/mbgl/style/bucket_parameters.cpp7
-rw-r--r--src/mbgl/style/bucket_parameters.hpp6
-rw-r--r--src/mbgl/style/calculation_parameters.hpp12
-rw-r--r--src/mbgl/style/cascade_parameters.hpp2
-rw-r--r--src/mbgl/style/filter_evaluator.hpp163
-rw-r--r--src/mbgl/style/layer.cpp8
-rw-r--r--src/mbgl/style/layer_impl.cpp14
-rw-r--r--src/mbgl/style/layer_impl.hpp13
-rw-r--r--src/mbgl/style/layers/background_layer.cpp20
-rw-r--r--src/mbgl/style/layers/background_layer_impl.cpp4
-rw-r--r--src/mbgl/style/layers/background_layer_impl.hpp4
-rw-r--r--src/mbgl/style/layers/background_layer_properties.cpp6
-rw-r--r--src/mbgl/style/layers/background_layer_properties.hpp5
-rw-r--r--src/mbgl/style/layers/circle_layer.cpp52
-rw-r--r--src/mbgl/style/layers/circle_layer_impl.cpp6
-rw-r--r--src/mbgl/style/layers/circle_layer_impl.hpp4
-rw-r--r--src/mbgl/style/layers/circle_layer_properties.cpp11
-rw-r--r--src/mbgl/style/layers/circle_layer_properties.hpp6
-rw-r--r--src/mbgl/style/layers/custom_layer_impl.cpp5
-rw-r--r--src/mbgl/style/layers/custom_layer_impl.hpp4
-rw-r--r--src/mbgl/style/layers/fill_layer.cpp48
-rw-r--r--src/mbgl/style/layers/fill_layer_impl.cpp6
-rw-r--r--src/mbgl/style/layers/fill_layer_impl.hpp4
-rw-r--r--src/mbgl/style/layers/fill_layer_properties.cpp10
-rw-r--r--src/mbgl/style/layers/fill_layer_properties.hpp7
-rw-r--r--src/mbgl/style/layers/layer.cpp.ejs100
-rw-r--r--src/mbgl/style/layers/layer_properties.cpp.ejs38
-rw-r--r--src/mbgl/style/layers/layer_properties.hpp.ejs54
-rw-r--r--src/mbgl/style/layers/line_layer.cpp60
-rw-r--r--src/mbgl/style/layers/line_layer_impl.cpp10
-rw-r--r--src/mbgl/style/layers/line_layer_impl.hpp4
-rw-r--r--src/mbgl/style/layers/line_layer_properties.cpp20
-rw-r--r--src/mbgl/style/layers/line_layer_properties.hpp6
-rw-r--r--src/mbgl/style/layers/raster_layer.cpp44
-rw-r--r--src/mbgl/style/layers/raster_layer_impl.cpp4
-rw-r--r--src/mbgl/style/layers/raster_layer_impl.hpp4
-rw-r--r--src/mbgl/style/layers/raster_layer_properties.cpp10
-rw-r--r--src/mbgl/style/layers/raster_layer_properties.hpp3
-rw-r--r--src/mbgl/style/layers/symbol_layer.cpp105
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.cpp21
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.hpp4
-rw-r--r--src/mbgl/style/layers/symbol_layer_properties.cpp54
-rw-r--r--src/mbgl/style/layers/symbol_layer_properties.hpp19
-rw-r--r--src/mbgl/style/layout_property.hpp7
-rw-r--r--src/mbgl/style/observer.hpp6
-rw-r--r--src/mbgl/style/paint_property.hpp65
-rw-r--r--src/mbgl/style/parser.cpp523
-rw-r--r--src/mbgl/style/parser.hpp9
-rw-r--r--src/mbgl/style/property_evaluator.cpp48
-rw-r--r--src/mbgl/style/property_evaluator.hpp10
-rw-r--r--src/mbgl/style/property_parsing.cpp263
-rw-r--r--src/mbgl/style/property_parsing.hpp98
-rw-r--r--src/mbgl/style/rapidjson_conversion.hpp94
-rw-r--r--src/mbgl/style/source.cpp420
-rw-r--r--src/mbgl/style/source.hpp112
-rw-r--r--src/mbgl/style/source_impl.cpp287
-rw-r--r--src/mbgl/style/source_impl.hpp101
-rw-r--r--src/mbgl/style/source_observer.hpp2
-rw-r--r--src/mbgl/style/sources/geojson_source.cpp26
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.cpp142
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.hpp40
-rw-r--r--src/mbgl/style/sources/raster_source.cpp12
-rw-r--r--src/mbgl/style/sources/raster_source_impl.cpp19
-rw-r--r--src/mbgl/style/sources/raster_source_impl.hpp18
-rw-r--r--src/mbgl/style/sources/vector_source.cpp12
-rw-r--r--src/mbgl/style/sources/vector_source_impl.cpp17
-rw-r--r--src/mbgl/style/sources/vector_source_impl.hpp18
-rw-r--r--src/mbgl/style/style.cpp93
-rw-r--r--src/mbgl/style/style.hpp9
-rw-r--r--src/mbgl/style/tile_source_impl.cpp118
-rw-r--r--src/mbgl/style/tile_source_impl.hpp48
-rw-r--r--src/mbgl/style/types.cpp92
-rw-r--r--src/mbgl/style/update_parameters.hpp6
-rw-r--r--src/mbgl/text/check_max_angle.hpp2
-rw-r--r--src/mbgl/text/collision_feature.cpp4
-rw-r--r--src/mbgl/text/collision_feature.hpp12
-rw-r--r--src/mbgl/text/collision_tile.cpp2
-rw-r--r--src/mbgl/text/get_anchors.cpp10
-rw-r--r--src/mbgl/text/get_anchors.hpp2
-rw-r--r--src/mbgl/text/glyph.hpp13
-rw-r--r--src/mbgl/text/glyph_pbf.cpp2
-rw-r--r--src/mbgl/text/glyph_pbf.hpp4
-rw-r--r--src/mbgl/text/glyph_set.cpp6
-rw-r--r--src/mbgl/text/glyph_set.hpp2
-rw-r--r--src/mbgl/text/placement_config.hpp6
-rw-r--r--src/mbgl/text/quads.cpp68
-rw-r--r--src/mbgl/text/quads.hpp28
-rw-r--r--src/mbgl/text/shaping.hpp6
-rw-r--r--src/mbgl/tile/geojson_tile.cpp197
-rw-r--r--src/mbgl/tile/geojson_tile.hpp73
-rw-r--r--src/mbgl/tile/geometry_tile.cpp342
-rw-r--r--src/mbgl/tile/geometry_tile.hpp139
-rw-r--r--src/mbgl/tile/geometry_tile_data.cpp217
-rw-r--r--src/mbgl/tile/geometry_tile_data.hpp143
-rw-r--r--src/mbgl/tile/raster_tile.cpp71
-rw-r--r--src/mbgl/tile/raster_tile.hpp46
-rw-r--r--src/mbgl/tile/raster_tile_data.cpp71
-rw-r--r--src/mbgl/tile/raster_tile_data.hpp39
-rw-r--r--src/mbgl/tile/tile.cpp35
-rw-r--r--src/mbgl/tile/tile.hpp111
-rw-r--r--src/mbgl/tile/tile_cache.cpp30
-rw-r--r--src/mbgl/tile/tile_cache.hpp8
-rw-r--r--src/mbgl/tile/tile_data.cpp25
-rw-r--r--src/mbgl/tile/tile_data.hpp87
-rw-r--r--src/mbgl/tile/tile_id.hpp23
-rw-r--r--src/mbgl/tile/tile_loader.hpp62
-rw-r--r--src/mbgl/tile/tile_loader_impl.hpp113
-rw-r--r--src/mbgl/tile/tile_observer.hpp18
-rw-r--r--src/mbgl/tile/tile_worker.cpp37
-rw-r--r--src/mbgl/tile/tile_worker.hpp20
-rw-r--r--src/mbgl/tile/vector_tile.cpp122
-rw-r--r--src/mbgl/tile/vector_tile.hpp83
-rw-r--r--src/mbgl/tile/vector_tile_data.cpp215
-rw-r--r--src/mbgl/tile/vector_tile_data.hpp75
-rw-r--r--src/mbgl/util/atomic.hpp45
-rw-r--r--src/mbgl/util/clip_id.hpp10
-rw-r--r--src/mbgl/util/color.cpp20
-rw-r--r--src/mbgl/util/convert.cpp9
-rw-r--r--src/mbgl/util/dtoa.cpp10
-rw-r--r--src/mbgl/util/dtoa.hpp9
-rw-r--r--src/mbgl/util/exclusive.hpp10
-rw-r--r--src/mbgl/util/geo.cpp4
-rw-r--r--src/mbgl/util/grid_index.cpp21
-rw-r--r--src/mbgl/util/grid_index.hpp2
-rw-r--r--src/mbgl/util/interpolate.hpp14
-rw-r--r--src/mbgl/util/intersection_tests.cpp4
-rw-r--r--src/mbgl/util/intersection_tests.hpp4
-rw-r--r--src/mbgl/util/io.hpp2
-rw-r--r--src/mbgl/util/mat2.cpp6
-rw-r--r--src/mbgl/util/mat3.cpp6
-rw-r--r--src/mbgl/util/math.cpp6
-rw-r--r--src/mbgl/util/math.hpp26
-rw-r--r--src/mbgl/util/ptr.hpp6
-rw-r--r--src/mbgl/util/raster.cpp88
-rw-r--r--src/mbgl/util/raster.hpp53
-rw-r--r--src/mbgl/util/rect.hpp10
-rw-r--r--src/mbgl/util/stopwatch.cpp15
-rw-r--r--src/mbgl/util/stopwatch.hpp16
-rw-r--r--src/mbgl/util/thread.hpp9
-rw-r--r--src/mbgl/util/thread_context.cpp5
-rw-r--r--src/mbgl/util/thread_context.hpp2
-rw-r--r--src/mbgl/util/thread_local.hpp10
-rw-r--r--src/mbgl/util/tile_coordinate.cpp1
-rw-r--r--src/mbgl/util/tileset.hpp24
-rw-r--r--src/mbgl/util/utf.hpp2
-rw-r--r--src/mbgl/util/version_info.cpp2
-rw-r--r--src/mbgl/util/work_task.cpp0
-rw-r--r--src/mbgl/util/worker.cpp10
-rw-r--r--src/mbgl/util/worker.hpp2
267 files changed, 5035 insertions, 4961 deletions
diff --git a/src/csscolorparser/csscolorparser.cpp b/src/csscolorparser/csscolorparser.cpp
index 8281eb4202..592f10f025 100644
--- a/src/csscolorparser/csscolorparser.cpp
+++ b/src/csscolorparser/csscolorparser.cpp
@@ -30,7 +30,7 @@
#include <cmath>
#include <algorithm>
-using namespace CSSColorParser;
+namespace CSSColorParser {
// http://www.w3.org/TR/css3-color/
struct NamedColor { const char *const name; const Color color; };
@@ -180,7 +180,7 @@ std::vector<std::string> split(const std::string& s, char delim) {
return elems;
}
-Color CSSColorParser::parse(const std::string& css_str) {
+Color parse(const std::string& css_str) {
std::string str = css_str;
// Remove all whitespace, not compliant, but should just be more accepting.
@@ -288,3 +288,5 @@ Color CSSColorParser::parse(const std::string& css_str) {
return {};
}
+
+} // namespace CSSColorParser
diff --git a/src/mbgl/algorithm/generate_clip_ids.cpp b/src/mbgl/algorithm/generate_clip_ids.cpp
index 208db797d0..74e0ee242f 100644
--- a/src/mbgl/algorithm/generate_clip_ids.cpp
+++ b/src/mbgl/algorithm/generate_clip_ids.cpp
@@ -2,7 +2,6 @@
#include <mbgl/algorithm/covered_by_children.hpp>
#include <mbgl/util/std.hpp>
-#include <mbgl/tile/tile.hpp>
#include <list>
#include <vector>
diff --git a/src/mbgl/algorithm/update_renderables.hpp b/src/mbgl/algorithm/update_renderables.hpp
index 22d4205d90..d47a919bae 100644
--- a/src/mbgl/algorithm/update_renderables.hpp
+++ b/src/mbgl/algorithm/update_renderables.hpp
@@ -1,24 +1,24 @@
#pragma once
#include <mbgl/tile/tile_id.hpp>
+#include <mbgl/util/range.hpp>
#include <set>
namespace mbgl {
namespace algorithm {
-template <typename GetTileDataFn,
- typename CreateTileDataFn,
- typename RetainTileDataFn,
+template <typename GetTileFn,
+ typename CreateTileFn,
+ typename RetainTileFn,
typename RenderTileFn,
- typename IdealTileIDs,
- typename SourceInfo>
-void updateRenderables(GetTileDataFn getTileData,
- CreateTileDataFn createTileData,
- RetainTileDataFn retainTileData,
+ typename IdealTileIDs>
+void updateRenderables(GetTileFn getTile,
+ CreateTileFn createTile,
+ RetainTileFn retainTile,
RenderTileFn renderTile,
const IdealTileIDs& idealTileIDs,
- const SourceInfo& info,
+ const Range<uint8_t>& zoomRange,
const uint8_t dataTileZoom) {
std::set<UnwrappedTileID> checked;
bool covered;
@@ -26,32 +26,34 @@ void updateRenderables(GetTileDataFn getTileData,
// for (all in the set of ideal tiles of the source) {
for (const auto& idealRenderTileID : idealTileIDs) {
- assert(idealRenderTileID.canonical.z >= info.minZoom);
- assert(idealRenderTileID.canonical.z <= info.maxZoom);
+ assert(idealRenderTileID.canonical.z >= zoomRange.min);
+ assert(idealRenderTileID.canonical.z <= zoomRange.max);
assert(dataTileZoom >= idealRenderTileID.canonical.z);
const OverscaledTileID idealDataTileID(dataTileZoom, idealRenderTileID.canonical);
- auto data = getTileData(idealDataTileID);
+ auto data = getTile(idealDataTileID);
if (!data) {
- data = createTileData(idealDataTileID);
+ data = createTile(idealDataTileID);
assert(data);
}
// if (source has the tile and bucket is loaded) {
if (data->isRenderable()) {
- retainTileData(*data);
+ retainTile(*data, true);
renderTile(idealRenderTileID, *data);
} else {
+ bool triedPrevious = data->hasTriedOptional();
+
// The tile isn't loaded yet, but retain it anyway because it's an ideal tile.
- retainTileData(*data);
+ retainTile(*data, true);
covered = true;
overscaledZ = dataTileZoom + 1;
- if (overscaledZ > info.maxZoom) {
+ if (overscaledZ > zoomRange.max) {
// We're looking for an overzoomed child tile.
const auto childDataTileID = idealDataTileID.scaledTo(overscaledZ);
- data = getTileData(childDataTileID);
+ data = getTile(childDataTileID);
if (data && data->isRenderable()) {
- retainTileData(*data);
+ retainTile(*data, false);
renderTile(idealRenderTileID, *data);
} else {
covered = false;
@@ -60,9 +62,9 @@ void updateRenderables(GetTileDataFn getTileData,
// Check all four actual child tiles.
for (const auto& childTileID : idealDataTileID.canonical.children()) {
const OverscaledTileID childDataTileID(overscaledZ, childTileID);
- data = getTileData(childDataTileID);
+ data = getTile(childDataTileID);
if (data && data->isRenderable()) {
- retainTileData(*data);
+ retainTile(*data, false);
renderTile(childDataTileID.unwrapTo(idealRenderTileID.wrap), *data);
} else {
// At least one child tile doesn't exist, so we are going to look for
@@ -74,7 +76,7 @@ void updateRenderables(GetTileDataFn getTileData,
if (!covered) {
// We couldn't find child tiles that entirely cover the ideal tile.
- for (overscaledZ = dataTileZoom - 1; overscaledZ >= info.minZoom; --overscaledZ) {
+ for (overscaledZ = dataTileZoom - 1; overscaledZ >= zoomRange.min; --overscaledZ) {
const auto parentDataTileID = idealDataTileID.scaledTo(overscaledZ);
const auto parentRenderTileID =
parentDataTileID.unwrapTo(idealRenderTileID.wrap);
@@ -87,12 +89,20 @@ void updateRenderables(GetTileDataFn getTileData,
checked.emplace(parentRenderTileID);
}
- data = getTileData(parentDataTileID);
- if (data && data->isRenderable()) {
- retainTileData(*data);
- renderTile(parentRenderTileID, *data);
- // Break parent tile ascent, since we found one.
- break;
+ data = getTile(parentDataTileID);
+ if (!data && triedPrevious) {
+ data = createTile(parentDataTileID);
+ }
+
+ if (data) {
+ triedPrevious = data->hasTriedOptional();
+ retainTile(*data, false);
+
+ if (data->isRenderable()) {
+ renderTile(parentRenderTileID, *data);
+ // Break parent tile ascent, since we found one.
+ break;
+ }
}
}
}
diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp
index 9a4f0a21ce..0cd6bdf231 100644
--- a/src/mbgl/annotation/annotation_manager.cpp
+++ b/src/mbgl/annotation/annotation_manager.cpp
@@ -1,10 +1,10 @@
#include <mbgl/annotation/annotation_manager.hpp>
+#include <mbgl/annotation/annotation_source.hpp>
#include <mbgl/annotation/annotation_tile.hpp>
#include <mbgl/annotation/symbol_annotation_impl.hpp>
#include <mbgl/annotation/line_annotation_impl.hpp>
#include <mbgl/annotation/fill_annotation_impl.hpp>
#include <mbgl/annotation/style_sourced_annotation_impl.hpp>
-#include <mbgl/style/source.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
@@ -31,10 +31,9 @@ AnnotationID AnnotationManager::addAnnotation(const Annotation& annotation, cons
return id;
}
-void AnnotationManager::updateAnnotation(const AnnotationID& id, const Annotation& annotation, const uint8_t maxZoom) {
- removeAnnotation(id);
- Annotation::visit(annotation, [&] (const auto& annotation_) {
- this->add(id, annotation_, maxZoom);
+Update AnnotationManager::updateAnnotation(const AnnotationID& id, const Annotation& annotation, const uint8_t maxZoom) {
+ return Annotation::visit(annotation, [&] (const auto& annotation_) {
+ return this->update(id, annotation_, maxZoom);
});
}
@@ -69,6 +68,53 @@ void AnnotationManager::add(const AnnotationID& id, const StyleSourcedAnnotation
std::make_unique<StyleSourcedAnnotationImpl>(id, annotation, maxZoom));
}
+Update AnnotationManager::update(const AnnotationID& id, const SymbolAnnotation& annotation, const uint8_t maxZoom) {
+ auto it = symbolAnnotations.find(id);
+ if (it == symbolAnnotations.end()) {
+ removeAndAdd(id, annotation, maxZoom);
+ return Update::AnnotationData | Update::AnnotationStyle;
+ }
+
+ Update result = Update::Nothing;
+ const SymbolAnnotation& existing = it->second->annotation;
+
+ if (existing.geometry != annotation.geometry) {
+ result |= Update::AnnotationData;
+ }
+
+ if (existing.icon != annotation.icon) {
+ result |= Update::AnnotationData | Update::AnnotationStyle;
+ }
+
+ if (result != Update::Nothing) {
+ removeAndAdd(id, annotation, maxZoom);
+ }
+
+ return result;
+}
+
+Update AnnotationManager::update(const AnnotationID& id, const LineAnnotation& annotation, const uint8_t maxZoom) {
+ removeAndAdd(id, annotation, maxZoom);
+ return Update::AnnotationData | Update::AnnotationStyle;
+}
+
+Update AnnotationManager::update(const AnnotationID& id, const FillAnnotation& annotation, const uint8_t maxZoom) {
+ removeAndAdd(id, annotation, maxZoom);
+ return Update::AnnotationData | Update::AnnotationStyle;
+}
+
+Update AnnotationManager::update(const AnnotationID& id, const StyleSourcedAnnotation& annotation, const uint8_t maxZoom) {
+ removeAndAdd(id, annotation, maxZoom);
+ return Update::AnnotationData | Update::AnnotationStyle;
+}
+
+void AnnotationManager::removeAndAdd(const AnnotationID& id, const Annotation& annotation, const uint8_t maxZoom) {
+ removeAnnotation(id);
+ Annotation::visit(annotation, [&] (const auto& annotation_) {
+ this->add(id, annotation_, maxZoom);
+ });
+}
+
AnnotationIDs AnnotationManager::getPointAnnotationsInBounds(const LatLngBounds& bounds) const {
AnnotationIDs result;
@@ -80,13 +126,13 @@ AnnotationIDs AnnotationManager::getPointAnnotationsInBounds(const LatLngBounds&
return result;
}
-std::unique_ptr<AnnotationTile> AnnotationManager::getTile(const CanonicalTileID& tileID) {
+std::unique_ptr<AnnotationTileData> AnnotationManager::getTileData(const CanonicalTileID& tileID) {
if (symbolAnnotations.empty() && shapeAnnotations.empty())
return nullptr;
- auto tile = std::make_unique<AnnotationTile>();
+ auto tileData = std::make_unique<AnnotationTileData>();
- AnnotationTileLayer& pointLayer = *tile->layers.emplace(
+ AnnotationTileLayer& pointLayer = *tileData->layers.emplace(
PointLayerID,
std::make_unique<AnnotationTileLayer>(PointLayerID)).first->second;
@@ -98,24 +144,22 @@ std::unique_ptr<AnnotationTile> AnnotationManager::getTile(const CanonicalTileID
}));
for (const auto& shape : shapeAnnotations) {
- shape.second->updateTile(tileID, *tile);
+ shape.second->updateTileData(tileID, *tileData);
}
- return tile;
+ return tileData;
}
void AnnotationManager::updateStyle(Style& style) {
// Create annotation source, point layer, and point bucket
if (!style.getSource(SourceID)) {
- auto tileset = std::make_unique<Tileset>();
- tileset->maxZoom = 18;
- std::unique_ptr<Source> source = std::make_unique<Source>(SourceType::Annotations, SourceID, "", util::tileSize, std::move(tileset), nullptr);
- source->enabled = true;
+ std::unique_ptr<Source> source = std::make_unique<AnnotationSource>();
+ source->baseImpl->enabled = true;
style.addSource(std::move(source));
- std::unique_ptr<SymbolLayer> layer = std::make_unique<SymbolLayer>(PointLayerID);
+ std::unique_ptr<SymbolLayer> layer = std::make_unique<SymbolLayer>(PointLayerID, SourceID);
- layer->setSource(SourceID, PointLayerID);
+ layer->setSourceLayer(PointLayerID);
layer->setIconImage({"{sprite}"});
layer->setIconAllowOverlap(true);
@@ -135,26 +179,28 @@ void AnnotationManager::updateStyle(Style& style) {
}
obsoleteShapeAnnotationLayers.clear();
+}
- for (auto& monitor : monitors) {
- monitor->update(getTile(monitor->tileID.canonical));
+void AnnotationManager::updateData() {
+ for (auto& tile : tiles) {
+ tile->setData(getTileData(tile->id.canonical));
}
}
-void AnnotationManager::addTileMonitor(AnnotationTileMonitor& monitor) {
- monitors.insert(&monitor);
- monitor.update(getTile(monitor.tileID.canonical));
+void AnnotationManager::addTile(AnnotationTile& tile) {
+ tiles.insert(&tile);
+ tile.setData(getTileData(tile.id.canonical));
}
-void AnnotationManager::removeTileMonitor(AnnotationTileMonitor& monitor) {
- monitors.erase(&monitor);
+void AnnotationManager::removeTile(AnnotationTile& tile) {
+ tiles.erase(&tile);
}
void AnnotationManager::addIcon(const std::string& name, std::shared_ptr<const SpriteImage> sprite) {
spriteStore.setSprite(name, sprite);
spriteAtlas.updateDirty();
}
-
+
void AnnotationManager::removeIcon(const std::string& name) {
spriteStore.removeSprite(name);
spriteAtlas.updateDirty();
diff --git a/src/mbgl/annotation/annotation_manager.hpp b/src/mbgl/annotation/annotation_manager.hpp
index 7e0cf3a394..ffe6cd163a 100644
--- a/src/mbgl/annotation/annotation_manager.hpp
+++ b/src/mbgl/annotation/annotation_manager.hpp
@@ -4,7 +4,7 @@
#include <mbgl/annotation/symbol_annotation_impl.hpp>
#include <mbgl/sprite/sprite_store.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/util/geo.hpp>
+#include <mbgl/map/update.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <string>
@@ -14,14 +14,15 @@
namespace mbgl {
+class LatLngBounds;
class AnnotationTile;
-class AnnotationTileMonitor;
+class AnnotationTileData;
class SymbolAnnotationImpl;
class ShapeAnnotationImpl;
namespace style {
class Style;
-}
+} // namespace style
class AnnotationManager : private util::noncopyable {
public:
@@ -29,7 +30,7 @@ public:
~AnnotationManager();
AnnotationID addAnnotation(const Annotation&, const uint8_t maxZoom);
- void updateAnnotation(const AnnotationID&, const Annotation&, const uint8_t maxZoom);
+ Update updateAnnotation(const AnnotationID&, const Annotation&, const uint8_t maxZoom);
void removeAnnotation(const AnnotationID&);
AnnotationIDs getPointAnnotationsInBounds(const LatLngBounds&) const;
@@ -40,9 +41,10 @@ public:
SpriteAtlas& getSpriteAtlas() { return spriteAtlas; }
void updateStyle(style::Style&);
+ void updateData();
- void addTileMonitor(AnnotationTileMonitor&);
- void removeTileMonitor(AnnotationTileMonitor&);
+ void addTile(AnnotationTile&);
+ void removeTile(AnnotationTile&);
static const std::string SourceID;
static const std::string PointLayerID;
@@ -53,7 +55,14 @@ private:
void add(const AnnotationID&, const FillAnnotation&, const uint8_t);
void add(const AnnotationID&, const StyleSourcedAnnotation&, const uint8_t);
- std::unique_ptr<AnnotationTile> getTile(const CanonicalTileID&);
+ Update update(const AnnotationID&, const SymbolAnnotation&, const uint8_t);
+ Update update(const AnnotationID&, const LineAnnotation&, const uint8_t);
+ Update update(const AnnotationID&, const FillAnnotation&, const uint8_t);
+ Update update(const AnnotationID&, const StyleSourcedAnnotation&, const uint8_t);
+
+ void removeAndAdd(const AnnotationID&, const Annotation&, const uint8_t);
+
+ std::unique_ptr<AnnotationTileData> getTileData(const CanonicalTileID&);
AnnotationID nextID = 0;
@@ -67,7 +76,7 @@ private:
SymbolAnnotationMap symbolAnnotations;
ShapeAnnotationMap shapeAnnotations;
std::vector<std::string> obsoleteShapeAnnotationLayers;
- std::set<AnnotationTileMonitor*> monitors;
+ std::set<AnnotationTile*> tiles;
SpriteStore spriteStore;
SpriteAtlas spriteAtlas;
diff --git a/src/mbgl/annotation/annotation_source.cpp b/src/mbgl/annotation/annotation_source.cpp
new file mode 100644
index 0000000000..61fc4ca2e4
--- /dev/null
+++ b/src/mbgl/annotation/annotation_source.cpp
@@ -0,0 +1,30 @@
+#include <mbgl/annotation/annotation_source.hpp>
+#include <mbgl/annotation/annotation_manager.hpp>
+#include <mbgl/annotation/annotation_tile.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+AnnotationSource::AnnotationSource()
+ : Source(SourceType::Annotations, std::make_unique<Impl>(*this)) {
+}
+
+AnnotationSource::Impl::Impl(Source& base_)
+ : Source::Impl(SourceType::Annotations, AnnotationManager::SourceID, base_) {
+}
+
+Range<uint8_t> AnnotationSource::Impl::getZoomRange() {
+ return { 0, 22 };
+}
+
+void AnnotationSource::Impl::load(FileSource&) {
+ loaded = true;
+}
+
+std::unique_ptr<Tile> AnnotationSource::Impl::createTile(const OverscaledTileID& tileID,
+ const style::UpdateParameters& parameters) {
+ return std::make_unique<AnnotationTile>(tileID, parameters);
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/annotation/annotation_source.hpp b/src/mbgl/annotation/annotation_source.hpp
new file mode 100644
index 0000000000..db9221788f
--- /dev/null
+++ b/src/mbgl/annotation/annotation_source.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <mbgl/style/source.hpp>
+#include <mbgl/style/source_impl.hpp>
+
+namespace mbgl {
+
+class AnnotationSource : public style::Source {
+public:
+ AnnotationSource();
+
+ class Impl;
+};
+
+class AnnotationSource::Impl : public style::Source::Impl {
+public:
+ Impl(Source&);
+
+ void load(FileSource&) final;
+
+private:
+ uint16_t getTileSize() const final { return util::tileSize; }
+ Range<uint8_t> getZoomRange() final;
+
+ std::unique_ptr<Tile> createTile(const OverscaledTileID&, const style::UpdateParameters&) final;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/annotation/annotation_tile.cpp b/src/mbgl/annotation/annotation_tile.cpp
index ba4b69108c..91b7f7ddc1 100644
--- a/src/mbgl/annotation/annotation_tile.cpp
+++ b/src/mbgl/annotation/annotation_tile.cpp
@@ -2,11 +2,25 @@
#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/storage/file_source.hpp>
+#include <mbgl/style/update_parameters.hpp>
#include <utility>
namespace mbgl {
+AnnotationTile::AnnotationTile(const OverscaledTileID& overscaledTileID,
+ const style::UpdateParameters& parameters)
+ : GeometryTile(overscaledTileID, AnnotationManager::SourceID, parameters.style, parameters.mode),
+ annotationManager(parameters.annotationManager) {
+ annotationManager.addTile(*this);
+}
+
+AnnotationTile::~AnnotationTile() {
+ annotationManager.removeTile(*this);
+}
+
+void AnnotationTile::setNecessity(Necessity) {}
+
AnnotationTileFeature::AnnotationTileFeature(FeatureType type_, GeometryCollection geometries_,
std::unordered_map<std::string, std::string> properties_)
: type(type_),
@@ -21,10 +35,10 @@ optional<Value> AnnotationTileFeature::getValue(const std::string& key) const {
return optional<Value>();
}
-AnnotationTileLayer::AnnotationTileLayer(const std::string &name_)
- : name(name_) {}
+AnnotationTileLayer::AnnotationTileLayer(std::string name_)
+ : name(std::move(name_)) {}
-util::ptr<GeometryTileLayer> AnnotationTile::getLayer(const std::string& name) const {
+util::ptr<GeometryTileLayer> AnnotationTileData::getLayer(const std::string& name) const {
auto it = layers.find(name);
if (it != layers.end()) {
return it->second;
@@ -32,23 +46,4 @@ util::ptr<GeometryTileLayer> AnnotationTile::getLayer(const std::string& name) c
return nullptr;
}
-AnnotationTileMonitor::AnnotationTileMonitor(const OverscaledTileID& tileID_, AnnotationManager& annotationManager_)
- : tileID(tileID_),
- annotationManager(annotationManager_) {
-}
-
-AnnotationTileMonitor::~AnnotationTileMonitor() {
- annotationManager.removeTileMonitor(*this);
-}
-
-std::unique_ptr<AsyncRequest> AnnotationTileMonitor::monitorTile(const GeometryTileMonitor::Callback& callback_) {
- callback = callback_;
- annotationManager.addTileMonitor(*this);
- return nullptr;
-}
-
-void AnnotationTileMonitor::update(std::unique_ptr<GeometryTile> tile) {
- callback(nullptr, std::move(tile), {}, {});
-}
-
} // namespace mbgl
diff --git a/src/mbgl/annotation/annotation_tile.hpp b/src/mbgl/annotation/annotation_tile.hpp
index d607d563d4..3e7c2c447f 100644
--- a/src/mbgl/annotation/annotation_tile.hpp
+++ b/src/mbgl/annotation/annotation_tile.hpp
@@ -1,13 +1,28 @@
#pragma once
#include <mbgl/tile/geometry_tile.hpp>
-#include <mbgl/tile/tile_id.hpp>
-
-#include <map>
-#include <unordered_map>
+#include <mbgl/tile/geometry_tile_data.hpp>
namespace mbgl {
+class AnnotationManager;
+
+namespace style {
+class UpdateParameters;
+} // namespace style
+
+class AnnotationTile : public GeometryTile {
+public:
+ AnnotationTile(const OverscaledTileID&,
+ const style::UpdateParameters&);
+ ~AnnotationTile() override;
+
+ void setNecessity(Necessity) final;
+
+private:
+ AnnotationManager& annotationManager;
+};
+
class AnnotationTileFeature : public GeometryTileFeature {
public:
AnnotationTileFeature(FeatureType, GeometryCollection,
@@ -24,7 +39,7 @@ public:
class AnnotationTileLayer : public GeometryTileLayer {
public:
- AnnotationTileLayer(const std::string&);
+ AnnotationTileLayer(std::string);
std::size_t featureCount() const override { return features.size(); }
util::ptr<const GeometryTileFeature> getFeature(std::size_t i) const override { return features[i]; }
@@ -36,28 +51,11 @@ private:
std::string name;
};
-class AnnotationTile : public GeometryTile {
+class AnnotationTileData : public GeometryTileData {
public:
util::ptr<GeometryTileLayer> getLayer(const std::string&) const override;
- std::map<std::string, util::ptr<AnnotationTileLayer>> layers;
-};
-
-class AnnotationManager;
-
-class AnnotationTileMonitor : public GeometryTileMonitor {
-public:
- AnnotationTileMonitor(const OverscaledTileID&, AnnotationManager&);
- ~AnnotationTileMonitor();
-
- void update(std::unique_ptr<GeometryTile>);
- std::unique_ptr<AsyncRequest> monitorTile(const GeometryTileMonitor::Callback&) override;
-
- OverscaledTileID tileID;
-
-private:
- AnnotationManager& annotationManager;
- GeometryTileMonitor::Callback callback;
+ std::unordered_map<std::string, util::ptr<AnnotationTileLayer>> layers;
};
} // namespace mbgl
diff --git a/src/mbgl/annotation/fill_annotation_impl.cpp b/src/mbgl/annotation/fill_annotation_impl.cpp
index 31c9f6d720..fe520451f7 100644
--- a/src/mbgl/annotation/fill_annotation_impl.cpp
+++ b/src/mbgl/annotation/fill_annotation_impl.cpp
@@ -7,18 +7,17 @@ namespace mbgl {
using namespace style;
-FillAnnotationImpl::FillAnnotationImpl(const AnnotationID id_, const FillAnnotation& annotation_, const uint8_t maxZoom_)
+FillAnnotationImpl::FillAnnotationImpl(AnnotationID id_, FillAnnotation annotation_, uint8_t maxZoom_)
: ShapeAnnotationImpl(id_, maxZoom_),
- annotation(annotation_) {
+ annotation({ ShapeAnnotationGeometry::visit(annotation_.geometry, CloseShapeAnnotation{}), annotation_.opacity, annotation_.color, annotation_.outlineColor }) {
}
void FillAnnotationImpl::updateStyle(Style& style) const {
if (style.getLayer(layerID))
return;
- std::unique_ptr<FillLayer> layer = std::make_unique<FillLayer>(layerID);
- layer->setSource(AnnotationManager::SourceID, layerID);
-
+ std::unique_ptr<FillLayer> layer = std::make_unique<FillLayer>(layerID, AnnotationManager::SourceID);
+ layer->setSourceLayer(layerID);
layer->setFillOpacity(annotation.opacity);
layer->setFillColor(annotation.color);
layer->setFillOutlineColor(annotation.outlineColor);
diff --git a/src/mbgl/annotation/fill_annotation_impl.hpp b/src/mbgl/annotation/fill_annotation_impl.hpp
index b879860c08..6376eee880 100644
--- a/src/mbgl/annotation/fill_annotation_impl.hpp
+++ b/src/mbgl/annotation/fill_annotation_impl.hpp
@@ -7,7 +7,7 @@ namespace mbgl {
class FillAnnotationImpl : public ShapeAnnotationImpl {
public:
- FillAnnotationImpl(const AnnotationID, const FillAnnotation&, const uint8_t maxZoom);
+ FillAnnotationImpl(AnnotationID, FillAnnotation, uint8_t maxZoom);
void updateStyle(style::Style&) const final;
const ShapeAnnotationGeometry& geometry() const final;
diff --git a/src/mbgl/annotation/line_annotation_impl.cpp b/src/mbgl/annotation/line_annotation_impl.cpp
index 85177591f4..f18ca9fadc 100644
--- a/src/mbgl/annotation/line_annotation_impl.cpp
+++ b/src/mbgl/annotation/line_annotation_impl.cpp
@@ -7,17 +7,17 @@ namespace mbgl {
using namespace style;
-LineAnnotationImpl::LineAnnotationImpl(const AnnotationID id_, const LineAnnotation& annotation_, const uint8_t maxZoom_)
+LineAnnotationImpl::LineAnnotationImpl(AnnotationID id_, LineAnnotation annotation_, uint8_t maxZoom_)
: ShapeAnnotationImpl(id_, maxZoom_),
- annotation(annotation_) {
+ annotation({ ShapeAnnotationGeometry::visit(annotation_.geometry, CloseShapeAnnotation{}), annotation_.opacity, annotation_.width, annotation_.color }) {
}
void LineAnnotationImpl::updateStyle(Style& style) const {
if (style.getLayer(layerID))
return;
- std::unique_ptr<LineLayer> layer = std::make_unique<LineLayer>(layerID);
- layer->setSource(AnnotationManager::SourceID, layerID);
+ std::unique_ptr<LineLayer> layer = std::make_unique<LineLayer>(layerID, AnnotationManager::SourceID);
+ layer->setSourceLayer(layerID);
layer->setLineJoin(LineJoinType::Round);
layer->setLineOpacity(annotation.opacity);
layer->setLineWidth(annotation.width);
diff --git a/src/mbgl/annotation/line_annotation_impl.hpp b/src/mbgl/annotation/line_annotation_impl.hpp
index c9a37dd390..7945da5d97 100644
--- a/src/mbgl/annotation/line_annotation_impl.hpp
+++ b/src/mbgl/annotation/line_annotation_impl.hpp
@@ -7,7 +7,7 @@ namespace mbgl {
class LineAnnotationImpl : public ShapeAnnotationImpl {
public:
- LineAnnotationImpl(const AnnotationID, const LineAnnotation&, const uint8_t maxZoom);
+ LineAnnotationImpl(AnnotationID, LineAnnotation, uint8_t maxZoom);
void updateStyle(style::Style&) const final;
const ShapeAnnotationGeometry& geometry() const final;
diff --git a/src/mbgl/annotation/shape_annotation_impl.cpp b/src/mbgl/annotation/shape_annotation_impl.cpp
index be6e12558d..445ee76511 100644
--- a/src/mbgl/annotation/shape_annotation_impl.cpp
+++ b/src/mbgl/annotation/shape_annotation_impl.cpp
@@ -1,5 +1,3 @@
-#include <mapbox/geojsonvt/convert.hpp>
-
#include <mbgl/annotation/shape_annotation_impl.hpp>
#include <mbgl/annotation/annotation_tile.hpp>
#include <mbgl/tile/tile_id.hpp>
@@ -7,6 +5,7 @@
#include <mbgl/math/clamp.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/constants.hpp>
+#include <mbgl/util/geometry.hpp>
namespace mbgl {
@@ -19,83 +18,14 @@ ShapeAnnotationImpl::ShapeAnnotationImpl(const AnnotationID id_, const uint8_t m
layerID("com.mapbox.annotations.shape." + util::toString(id)) {
}
-struct ToGeoJSONVT {
- const double tolerance;
-
- ToGeoJSONVT(const double tolerance_)
- : tolerance(tolerance_) {
- }
-
- geojsonvt::ProjectedFeature operator()(const LineString<double>& line) const {
- geojsonvt::ProjectedRings converted;
- converted.push_back(convertPoints(geojsonvt::ProjectedFeatureType::LineString, line));
- return convertFeature(geojsonvt::ProjectedFeatureType::LineString, converted);
- }
-
- geojsonvt::ProjectedFeature operator()(const Polygon<double>& polygon) const {
- geojsonvt::ProjectedRings converted;
- for (const auto& ring : polygon) {
- converted.push_back(convertPoints(geojsonvt::ProjectedFeatureType::Polygon, ring));
- }
- return convertFeature(geojsonvt::ProjectedFeatureType::Polygon, converted);
- }
-
- geojsonvt::ProjectedFeature operator()(const MultiLineString<double>& lines) const {
- geojsonvt::ProjectedRings converted;
- for (const auto& line : lines) {
- converted.push_back(convertPoints(geojsonvt::ProjectedFeatureType::LineString, line));
- }
- return convertFeature(geojsonvt::ProjectedFeatureType::LineString, converted);
- }
-
- geojsonvt::ProjectedFeature operator()(const MultiPolygon<double>& polygons) const {
- geojsonvt::ProjectedRings converted;
- for (const auto& polygon : polygons) {
- for (const auto& ring : polygon) {
- converted.push_back(convertPoints(geojsonvt::ProjectedFeatureType::Polygon, ring));
- }
- }
- return convertFeature(geojsonvt::ProjectedFeatureType::Polygon, converted);
- }
-
-private:
- geojsonvt::LonLat convertPoint(const Point<double>& p) const {
- return {
- util::wrap(p.x, -util::LONGITUDE_MAX, util::LONGITUDE_MAX),
- util::clamp(p.y, -util::LATITUDE_MAX, util::LATITUDE_MAX)
- };
- }
-
- geojsonvt::ProjectedRing convertPoints(geojsonvt::ProjectedFeatureType type, const std::vector<Point<double>>& points) const {
- std::vector<geojsonvt::LonLat> converted;
-
- for (const auto& p : points) {
- converted.push_back(convertPoint(p));
- }
-
- if (type == geojsonvt::ProjectedFeatureType::Polygon && points.front() != points.back()) {
- converted.push_back(converted.front());
- }
-
- return geojsonvt::Convert::projectRing(converted, tolerance);
- }
-
- geojsonvt::ProjectedFeature convertFeature(geojsonvt::ProjectedFeatureType type, const geojsonvt::ProjectedRings& rings) const {
- return geojsonvt::Convert::create(geojsonvt::Tags(), type, rings);
- }
-};
-
-void ShapeAnnotationImpl::updateTile(const CanonicalTileID& tileID, AnnotationTile& tile) {
+void ShapeAnnotationImpl::updateTileData(const CanonicalTileID& tileID, AnnotationTileData& data) {
static const double baseTolerance = 4;
if (!shapeTiler) {
- const uint64_t maxAmountOfTiles = 1 << maxZoom;
- const double tolerance = baseTolerance / (maxAmountOfTiles * util::EXTENT);
-
- std::vector<geojsonvt::ProjectedFeature> features = {
- ShapeAnnotationGeometry::visit(geometry(), ToGeoJSONVT(tolerance))
- };
-
+ mapbox::geometry::feature_collection<double> features;
+ features.emplace_back(ShapeAnnotationGeometry::visit(geometry(), [] (auto&& geom) {
+ return Feature { std::move(geom) };
+ }));
mapbox::geojsonvt::Options options;
options.maxZoom = maxZoom;
options.buffer = 255u;
@@ -105,34 +35,20 @@ void ShapeAnnotationImpl::updateTile(const CanonicalTileID& tileID, AnnotationTi
}
const auto& shapeTile = shapeTiler->getTile(tileID.z, tileID.x, tileID.y);
- if (!shapeTile)
+ if (shapeTile.features.empty())
return;
- AnnotationTileLayer& layer = *tile.layers.emplace(layerID,
+ AnnotationTileLayer& layer = *data.layers.emplace(layerID,
std::make_unique<AnnotationTileLayer>(layerID)).first->second;
- for (auto& shapeFeature : shapeTile.features) {
- FeatureType featureType = FeatureType::Unknown;
-
- if (shapeFeature.type == geojsonvt::TileFeatureType::LineString) {
- featureType = FeatureType::LineString;
- } else if (shapeFeature.type == geojsonvt::TileFeatureType::Polygon) {
- featureType = FeatureType::Polygon;
- }
+ ToGeometryCollection toGeometryCollection;
+ ToFeatureType toFeatureType;
+ for (const auto& shapeFeature : shapeTile.features) {
+ FeatureType featureType = apply_visitor(toFeatureType, shapeFeature.geometry);
+ GeometryCollection renderGeometry = apply_visitor(toGeometryCollection, shapeFeature.geometry);
assert(featureType != FeatureType::Unknown);
- GeometryCollection renderGeometry;
- for (auto& shapeRing : shapeFeature.tileGeometry.get<geojsonvt::TileRings>()) {
- GeometryCoordinates renderLine;
-
- for (auto& shapePoint : shapeRing) {
- renderLine.emplace_back(shapePoint.x, shapePoint.y);
- }
-
- renderGeometry.push_back(renderLine);
- }
-
// https://github.com/mapbox/geojson-vt-cpp/issues/44
if (featureType == FeatureType::Polygon) {
renderGeometry = fixupPolygons(renderGeometry);
diff --git a/src/mbgl/annotation/shape_annotation_impl.hpp b/src/mbgl/annotation/shape_annotation_impl.hpp
index e6ba9a4bd7..800b4ec313 100644
--- a/src/mbgl/annotation/shape_annotation_impl.hpp
+++ b/src/mbgl/annotation/shape_annotation_impl.hpp
@@ -3,18 +3,19 @@
#include <mapbox/geojsonvt.hpp>
#include <mbgl/annotation/annotation.hpp>
+#include <mbgl/util/geometry.hpp>
#include <string>
#include <memory>
namespace mbgl {
-class AnnotationTile;
+class AnnotationTileData;
class CanonicalTileID;
namespace style {
class Style;
-}
+} // namespace style
class ShapeAnnotationImpl {
public:
@@ -24,7 +25,7 @@ public:
virtual void updateStyle(style::Style&) const = 0;
virtual const ShapeAnnotationGeometry& geometry() const = 0;
- void updateTile(const CanonicalTileID&, AnnotationTile&);
+ void updateTileData(const CanonicalTileID&, AnnotationTileData&);
const AnnotationID id;
const uint8_t maxZoom;
@@ -32,4 +33,33 @@ public:
std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> shapeTiler;
};
+struct CloseShapeAnnotation {
+ ShapeAnnotationGeometry operator()(const mbgl::LineString<double> &geom) const {
+ return geom;
+ }
+ ShapeAnnotationGeometry operator()(const mbgl::MultiLineString<double> &geom) const {
+ return geom;
+ }
+ ShapeAnnotationGeometry operator()(const mbgl::Polygon<double> &geom) const {
+ mbgl::Polygon<double> closed = geom;
+ for (auto &ring : closed) {
+ if (!ring.empty() && ring.front() != ring.back()) {
+ ring.emplace_back(ring.front());
+ }
+ }
+ return closed;
+ }
+ ShapeAnnotationGeometry operator()(const mbgl::MultiPolygon<double> &geom) const {
+ mbgl::MultiPolygon<double> closed = geom;
+ for (auto &polygon : closed) {
+ for (auto &ring : polygon) {
+ if (!ring.empty() && ring.front() != ring.back()) {
+ ring.emplace_back(ring.front());
+ }
+ }
+ }
+ return closed;
+ }
+};
+
} // namespace mbgl
diff --git a/src/mbgl/annotation/style_sourced_annotation_impl.cpp b/src/mbgl/annotation/style_sourced_annotation_impl.cpp
index 43a27c8aac..d3212da12d 100644
--- a/src/mbgl/annotation/style_sourced_annotation_impl.cpp
+++ b/src/mbgl/annotation/style_sourced_annotation_impl.cpp
@@ -2,6 +2,7 @@
#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/layer.hpp>
+#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
@@ -9,9 +10,9 @@ namespace mbgl {
using namespace style;
-StyleSourcedAnnotationImpl::StyleSourcedAnnotationImpl(const AnnotationID id_, const StyleSourcedAnnotation& annotation_, const uint8_t maxZoom_)
+StyleSourcedAnnotationImpl::StyleSourcedAnnotationImpl(AnnotationID id_, StyleSourcedAnnotation annotation_, uint8_t maxZoom_)
: ShapeAnnotationImpl(id_, maxZoom_),
- annotation(annotation_) {
+ annotation(std::move(annotation_)) {
}
void StyleSourcedAnnotationImpl::updateStyle(Style& style) const {
@@ -23,13 +24,13 @@ void StyleSourcedAnnotationImpl::updateStyle(Style& style) const {
return;
if (sourceLayer->is<LineLayer>()) {
- std::unique_ptr<Layer> layer = sourceLayer->copy(layerID, "");
- layer->as<LineLayer>()->setSource(AnnotationManager::SourceID, layerID);
+ std::unique_ptr<Layer> layer = sourceLayer->baseImpl->copy(layerID, "", AnnotationManager::SourceID);
+ layer->as<LineLayer>()->setSourceLayer(layerID);
layer->as<LineLayer>()->setVisibility(VisibilityType::Visible);
style.addLayer(std::move(layer), sourceLayer->getID());
} else if (sourceLayer->is<FillLayer>()) {
- std::unique_ptr<Layer> layer = sourceLayer->copy(layerID, "");
- layer->as<FillLayer>()->setSource(AnnotationManager::SourceID, layerID);
+ std::unique_ptr<Layer> layer = sourceLayer->baseImpl->copy(layerID, "", AnnotationManager::SourceID);
+ layer->as<FillLayer>()->setSourceLayer(layerID);
layer->as<FillLayer>()->setVisibility(VisibilityType::Visible);
style.addLayer(std::move(layer), sourceLayer->getID());
}
diff --git a/src/mbgl/annotation/style_sourced_annotation_impl.hpp b/src/mbgl/annotation/style_sourced_annotation_impl.hpp
index 09ef474fc0..82b947302d 100644
--- a/src/mbgl/annotation/style_sourced_annotation_impl.hpp
+++ b/src/mbgl/annotation/style_sourced_annotation_impl.hpp
@@ -7,7 +7,7 @@ namespace mbgl {
class StyleSourcedAnnotationImpl : public ShapeAnnotationImpl {
public:
- StyleSourcedAnnotationImpl(const AnnotationID, const StyleSourcedAnnotation&, const uint8_t maxZoom);
+ StyleSourcedAnnotationImpl(AnnotationID, StyleSourcedAnnotation, uint8_t maxZoom);
void updateStyle(style::Style&) const final;
const ShapeAnnotationGeometry& geometry() const final;
diff --git a/src/mbgl/annotation/symbol_annotation_impl.cpp b/src/mbgl/annotation/symbol_annotation_impl.cpp
index 44a89576bb..5ac2581949 100644
--- a/src/mbgl/annotation/symbol_annotation_impl.cpp
+++ b/src/mbgl/annotation/symbol_annotation_impl.cpp
@@ -1,12 +1,13 @@
#include <mbgl/annotation/symbol_annotation_impl.hpp>
#include <mbgl/annotation/annotation_tile.hpp>
+#include <mbgl/tile/tile_id.hpp>
#include <mbgl/math/clamp.hpp>
namespace mbgl {
-SymbolAnnotationImpl::SymbolAnnotationImpl(const AnnotationID id_, const SymbolAnnotation& annotation_)
+SymbolAnnotationImpl::SymbolAnnotationImpl(AnnotationID id_, SymbolAnnotation annotation_)
: id(id_),
- annotation(annotation_) {
+ annotation(std::move(annotation_)) {
}
void SymbolAnnotationImpl::updateLayer(const CanonicalTileID& tileID, AnnotationTileLayer& layer) const {
diff --git a/src/mbgl/annotation/symbol_annotation_impl.hpp b/src/mbgl/annotation/symbol_annotation_impl.hpp
index 5dc882ab93..2e98f2414c 100644
--- a/src/mbgl/annotation/symbol_annotation_impl.hpp
+++ b/src/mbgl/annotation/symbol_annotation_impl.hpp
@@ -37,7 +37,7 @@ class CanonicalTileID;
class SymbolAnnotationImpl {
public:
- SymbolAnnotationImpl(const AnnotationID, const SymbolAnnotation&);
+ SymbolAnnotationImpl(AnnotationID, SymbolAnnotation);
void updateLayer(const CanonicalTileID&, AnnotationTileLayer&) const;
@@ -55,7 +55,7 @@ namespace index {
template <>
struct indexable<std::shared_ptr<const mbgl::SymbolAnnotationImpl>> {
using result_type = mbgl::LatLng;
- inline mbgl::LatLng operator()(const std::shared_ptr<const mbgl::SymbolAnnotationImpl>& v) const {
+ mbgl::LatLng operator()(const std::shared_ptr<const mbgl::SymbolAnnotationImpl>& v) const {
const mbgl::Point<double>& p = v->annotation.geometry;
return mbgl::LatLng(p.y, p.x);
}
diff --git a/src/mbgl/geometry/buffer.hpp b/src/mbgl/geometry/buffer.hpp
index 6465b6f8e3..d372a040bf 100644
--- a/src/mbgl/geometry/buffer.hpp
+++ b/src/mbgl/geometry/buffer.hpp
@@ -27,11 +27,11 @@ public:
// Returns the number of elements in this buffer. This is not the number of
// bytes, but rather the number of coordinates with associated information.
- inline GLsizei index() const {
+ GLsizei index() const {
return static_cast<GLsizei>(pos / itemSize);
}
- inline bool empty() const {
+ bool empty() const {
return pos == 0;
}
@@ -65,7 +65,7 @@ public:
}
// Uploads the buffer to the GPU to be available when we need it.
- inline void upload(gl::ObjectStore& store) {
+ void upload(gl::ObjectStore& store) {
if (!buffer) {
bind(store);
}
@@ -73,7 +73,7 @@ public:
protected:
// increase the buffer size by at least /required/ bytes.
- inline void *addElement() {
+ void *addElement() {
if (buffer) {
throw std::runtime_error("Can't add elements after buffer was bound to GPU");
}
diff --git a/src/mbgl/geometry/circle_buffer.cpp b/src/mbgl/geometry/circle_buffer.cpp
index 74ccfa8267..cc31fb83bf 100644
--- a/src/mbgl/geometry/circle_buffer.cpp
+++ b/src/mbgl/geometry/circle_buffer.cpp
@@ -4,10 +4,12 @@
#include <climits>
-using namespace mbgl;
+namespace mbgl {
void CircleVertexBuffer::add(vertex_type x, vertex_type y, float ex, float ey) {
vertex_type *vertices = static_cast<vertex_type *>(addElement());
vertices[0] = (x * 2) + ((ex + 1) / 2);
vertices[1] = (y * 2) + ((ey + 1) / 2);
}
+
+} // namespace mbgl
diff --git a/src/mbgl/geometry/debug_font_buffer.cpp b/src/mbgl/geometry/debug_font_buffer.cpp
index 5df67accd6..f64ce8816b 100644
--- a/src/mbgl/geometry/debug_font_buffer.cpp
+++ b/src/mbgl/geometry/debug_font_buffer.cpp
@@ -5,7 +5,7 @@
#include <cmath>
#include <cstring>
-using namespace mbgl;
+namespace mbgl {
void DebugFontBuffer::addText(const char *text, double left, double baseline, double scale) {
uint16_t *coords = nullptr;
@@ -40,3 +40,5 @@ void DebugFontBuffer::addText(const char *text, double left, double baseline, do
left += glyph.width * scale;
}
}
+
+} // namespace mbgl
diff --git a/src/mbgl/geometry/elements_buffer.cpp b/src/mbgl/geometry/elements_buffer.cpp
index 3e2e2794dd..b7d8cb2015 100644
--- a/src/mbgl/geometry/elements_buffer.cpp
+++ b/src/mbgl/geometry/elements_buffer.cpp
@@ -1,6 +1,6 @@
#include <mbgl/geometry/elements_buffer.hpp>
-using namespace mbgl;
+namespace mbgl {
void TriangleElementsBuffer::add(element_type a, element_type b, element_type c) {
element_type *elements = static_cast<element_type *>(addElement());
@@ -14,3 +14,5 @@ void LineElementsBuffer::add(element_type a, element_type b) {
elements[0] = a;
elements[1] = b;
}
+
+} // namespace mbgl
diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp
index 8c10344915..6d6521917e 100644
--- a/src/mbgl/geometry/feature_index.cpp
+++ b/src/mbgl/geometry/feature_index.cpp
@@ -57,7 +57,7 @@ void FeatureIndex::query(
const double tileSize,
const double scale,
const optional<std::vector<std::string>>& filterLayerIDs,
- const GeometryTile& geometryTile,
+ const GeometryTileData& geometryTileData,
const CanonicalTileID& tileID,
const style::Style& style) const {
@@ -75,7 +75,7 @@ void FeatureIndex::query(
if (indexedFeature.sortIndex == previousSortIndex) continue;
previousSortIndex = indexedFeature.sortIndex;
- addFeature(result, indexedFeature, queryGeometry, filterLayerIDs, geometryTile, tileID, style, bearing, pixelsToTileUnits);
+ addFeature(result, indexedFeature, queryGeometry, filterLayerIDs, geometryTileData, tileID, style, bearing, pixelsToTileUnits);
}
// query symbol features
@@ -83,7 +83,7 @@ void FeatureIndex::query(
std::vector<IndexedSubfeature> symbolFeatures = collisionTile->queryRenderedSymbols(box, scale);
std::sort(symbolFeatures.begin(), symbolFeatures.end(), topDownSymbols);
for (const auto& symbolFeature : symbolFeatures) {
- addFeature(result, symbolFeature, queryGeometry, filterLayerIDs, geometryTile, tileID, style, bearing, pixelsToTileUnits);
+ addFeature(result, symbolFeature, queryGeometry, filterLayerIDs, geometryTileData, tileID, style, bearing, pixelsToTileUnits);
}
}
@@ -92,7 +92,7 @@ void FeatureIndex::addFeature(
const IndexedSubfeature& indexedFeature,
const GeometryCollection& queryGeometry,
const optional<std::vector<std::string>>& filterLayerIDs,
- const GeometryTile& geometryTile,
+ const GeometryTileData& geometryTileData,
const CanonicalTileID& tileID,
const style::Style& style,
const float bearing,
@@ -103,7 +103,7 @@ void FeatureIndex::addFeature(
return;
}
- auto sourceLayer = geometryTile.getLayer(indexedFeature.sourceLayerName);
+ auto sourceLayer = geometryTileData.getLayer(indexedFeature.sourceLayerName);
assert(sourceLayer);
auto geometryTileFeature = sourceLayer->getFeature(indexedFeature.index);
diff --git a/src/mbgl/geometry/feature_index.hpp b/src/mbgl/geometry/feature_index.hpp
index c944a98130..0fddcb4700 100644
--- a/src/mbgl/geometry/feature_index.hpp
+++ b/src/mbgl/geometry/feature_index.hpp
@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/style/types.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/util/grid_index.hpp>
#include <mbgl/util/feature.hpp>
@@ -13,7 +13,7 @@ namespace mbgl {
namespace style {
class Style;
-}
+} // namespace style
class CollisionTile;
class CanonicalTileID;
@@ -40,7 +40,7 @@ public:
const double tileSize,
const double scale,
const optional<std::vector<std::string>>& layerIDs,
- const GeometryTile&,
+ const GeometryTileData&,
const CanonicalTileID&,
const style::Style&) const;
@@ -61,7 +61,7 @@ private:
const IndexedSubfeature&,
const GeometryCollection& queryGeometry,
const optional<std::vector<std::string>>& filterLayerIDs,
- const GeometryTile&,
+ const GeometryTileData&,
const CanonicalTileID&,
const style::Style&,
const float bearing,
@@ -73,4 +73,4 @@ private:
std::unordered_map<std::string, std::vector<std::string>> bucketLayerIDs;
};
-}
+} // namespace mbgl
diff --git a/src/mbgl/geometry/fill_buffer.cpp b/src/mbgl/geometry/fill_buffer.cpp
index ee70dfc53b..6cb07ea66a 100644
--- a/src/mbgl/geometry/fill_buffer.cpp
+++ b/src/mbgl/geometry/fill_buffer.cpp
@@ -4,10 +4,12 @@
#include <climits>
-using namespace mbgl;
+namespace mbgl {
void FillVertexBuffer::add(vertex_type x, vertex_type y) {
vertex_type *vertices = static_cast<vertex_type *>(addElement());
vertices[0] = x;
vertices[1] = y;
}
+
+} // namespace mbgl
diff --git a/src/mbgl/geometry/glyph_atlas.cpp b/src/mbgl/geometry/glyph_atlas.cpp
index b4687b8e07..cfc5962eb3 100644
--- a/src/mbgl/geometry/glyph_atlas.cpp
+++ b/src/mbgl/geometry/glyph_atlas.cpp
@@ -2,6 +2,7 @@
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/object_store.hpp>
+#include <mbgl/gl/gl_config.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/platform/platform.hpp>
@@ -9,7 +10,7 @@
#include <algorithm>
-using namespace mbgl;
+namespace mbgl {
GlyphAtlas::GlyphAtlas(uint16_t width_, uint16_t height_)
: width(width_),
@@ -19,8 +20,7 @@ GlyphAtlas::GlyphAtlas(uint16_t width_, uint16_t height_)
dirty(true) {
}
-GlyphAtlas::~GlyphAtlas() {
-}
+GlyphAtlas::~GlyphAtlas() = default;
void GlyphAtlas::addGlyphs(uintptr_t tileUID,
const std::u32string& text,
@@ -53,7 +53,7 @@ Rect<uint16_t> GlyphAtlas::addGlyph(uintptr_t tileUID,
const uint8_t buffer = 3;
std::map<uint32_t, GlyphValue>& face = index[fontStack];
- std::map<uint32_t, GlyphValue>::iterator it = face.find(glyph.id);
+ auto it = face.find(glyph.id);
// The glyph is already in this texture.
if (it != face.end()) {
@@ -142,13 +142,14 @@ void GlyphAtlas::removeGlyphs(uintptr_t tileUID) {
}
}
-void GlyphAtlas::upload(gl::ObjectStore& store) {
+void GlyphAtlas::upload(gl::ObjectStore& store, gl::Config& config, uint32_t unit) {
if (dirty) {
const bool first = !texture;
- bind(store);
+ bind(store, config, unit);
std::lock_guard<std::mutex> lock(mtx);
+ config.activeTexture = unit;
if (first) {
MBGL_CHECK_ERROR(glTexImage2D(
GL_TEXTURE_2D, // GLenum target
@@ -183,10 +184,11 @@ void GlyphAtlas::upload(gl::ObjectStore& store) {
}
}
-void GlyphAtlas::bind(gl::ObjectStore& store) {
+void GlyphAtlas::bind(gl::ObjectStore& store, gl::Config& config, uint32_t unit) {
if (!texture) {
texture = store.createTexture();
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
+ config.activeTexture = unit;
+ config.texture[unit] = *texture;
#ifndef GL_ES_VERSION_2_0
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
#endif
@@ -194,7 +196,10 @@ void GlyphAtlas::bind(gl::ObjectStore& store) {
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
- } else {
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
+ } else if (config.texture[unit] != *texture) {
+ config.activeTexture = unit;
+ config.texture[unit] = *texture;
}
-};
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/geometry/glyph_atlas.hpp b/src/mbgl/geometry/glyph_atlas.hpp
index d3e2a62199..b9170c1caf 100644
--- a/src/mbgl/geometry/glyph_atlas.hpp
+++ b/src/mbgl/geometry/glyph_atlas.hpp
@@ -2,12 +2,12 @@
#include <mbgl/geometry/binpack.hpp>
#include <mbgl/text/glyph_store.hpp>
-#include <mbgl/util/atomic.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/object_store.hpp>
+#include <atomic>
#include <string>
#include <set>
#include <unordered_map>
@@ -15,6 +15,10 @@
namespace mbgl {
+namespace gl {
+class Config;
+} // namespace gl
+
class GlyphAtlas : public util::noncopyable {
public:
GlyphAtlas(uint16_t width, uint16_t height);
@@ -28,19 +32,19 @@ public:
void removeGlyphs(uintptr_t tileUID);
// Binds the atlas texture to the GPU, and uploads data if it is out of date.
- void bind(gl::ObjectStore&);
+ void bind(gl::ObjectStore&, gl::Config&, uint32_t unit);
// Uploads the texture to the GPU to be available when we need it. This is a lazy operation;
// the texture is only bound when the data is out of date (=dirty).
- void upload(gl::ObjectStore&);
+ void upload(gl::ObjectStore&, gl::Config&, uint32_t unit);
const GLsizei width;
const GLsizei height;
private:
struct GlyphValue {
- GlyphValue(const Rect<uint16_t>& rect_, uintptr_t id)
- : rect(rect_), ids({ id }) {}
+ GlyphValue(Rect<uint16_t> rect_, uintptr_t id)
+ : rect(std::move(rect_)), ids({ id }) {}
Rect<uint16_t> rect;
std::set<uintptr_t> ids;
};
@@ -53,7 +57,7 @@ private:
BinPack<uint16_t> bin;
std::unordered_map<FontStack, std::map<uint32_t, GlyphValue>, FontStackHash> index;
const std::unique_ptr<uint8_t[]> data;
- util::Atomic<bool> dirty;
+ std::atomic<bool> dirty;
mbgl::optional<gl::UniqueTexture> texture;
};
diff --git a/src/mbgl/geometry/icon_buffer.cpp b/src/mbgl/geometry/icon_buffer.cpp
index 101132ddbc..51a4aa69fd 100644
--- a/src/mbgl/geometry/icon_buffer.cpp
+++ b/src/mbgl/geometry/icon_buffer.cpp
@@ -6,7 +6,7 @@
namespace mbgl {
-size_t IconVertexBuffer::add(int16_t x, int16_t y, float ox, float oy, int16_t tx, int16_t ty, float minzoom, float maxzoom, float labelminzoom) {
+size_t IconVertexBuffer::add(int16_t x, int16_t y, float ox, float oy, int16_t tx, int16_t ty, float minzoom, float maxzoom, float labelminzoom, uint8_t labelangle) {
const size_t idx = index();
void *data = addElement();
@@ -21,6 +21,7 @@ size_t IconVertexBuffer::add(int16_t x, int16_t y, float ox, float oy, int16_t t
ubytes[8] /* tex */ = tx / 4;
ubytes[9] /* tex */ = ty / 4;
ubytes[10] /* labelminzoom */ = labelminzoom * 10;
+ ubytes[11] /* labelangle */ = labelangle;
// a_data2
ubytes[12] /* minzoom */ = minzoom * 10; // 1/10 zoom levels: z16 == 160.
diff --git a/src/mbgl/geometry/icon_buffer.hpp b/src/mbgl/geometry/icon_buffer.hpp
index 0116686265..3a1d57ccd7 100644
--- a/src/mbgl/geometry/icon_buffer.hpp
+++ b/src/mbgl/geometry/icon_buffer.hpp
@@ -10,7 +10,7 @@ namespace mbgl {
16
> {
public:
- size_t add(int16_t x, int16_t y, float ox, float oy, int16_t tx, int16_t ty, float minzoom, float maxzoom, float labelminzoom);
+ size_t add(int16_t x, int16_t y, float ox, float oy, int16_t tx, int16_t ty, float minzoom, float maxzoom, float labelminzoom, uint8_t labelangle);
};
diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp
index 830640f780..f08ea1e5fc 100644
--- a/src/mbgl/geometry/line_atlas.cpp
+++ b/src/mbgl/geometry/line_atlas.cpp
@@ -1,6 +1,7 @@
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/object_store.hpp>
+#include <mbgl/gl/gl_config.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/platform/platform.hpp>
@@ -9,7 +10,7 @@
#include <sstream>
#include <cmath>
-using namespace mbgl;
+namespace mbgl {
LineAtlas::LineAtlas(GLsizei w, GLsizei h)
: width(w),
@@ -18,10 +19,9 @@ LineAtlas::LineAtlas(GLsizei w, GLsizei h)
dirty(true) {
}
-LineAtlas::~LineAtlas() {
-}
+LineAtlas::~LineAtlas() = default;
-LinePatternPos LineAtlas::getDashPosition(const std::vector<float> &dasharray, bool round, gl::ObjectStore& store) {
+LinePatternPos LineAtlas::getDashPosition(const std::vector<float>& dasharray, bool round) {
size_t key = round ? std::numeric_limits<size_t>::min() : std::numeric_limits<size_t>::max();
for (const float part : dasharray) {
boost::hash_combine<float>(key, part);
@@ -30,7 +30,7 @@ LinePatternPos LineAtlas::getDashPosition(const std::vector<float> &dasharray, b
// Note: We're not handling hash collisions here.
const auto it = positions.find(key);
if (it == positions.end()) {
- auto inserted = positions.emplace(key, addDash(dasharray, round, store));
+ auto inserted = positions.emplace(key, addDash(dasharray, round));
assert(inserted.second);
return inserted.first->second;
} else {
@@ -38,8 +38,7 @@ LinePatternPos LineAtlas::getDashPosition(const std::vector<float> &dasharray, b
}
}
-LinePatternPos LineAtlas::addDash(const std::vector<float> &dasharray, bool round, gl::ObjectStore& store) {
-
+LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, bool round) {
int n = round ? 7 : 0;
int dashheight = 2 * n + 1;
const uint8_t offset = 128;
@@ -116,32 +115,34 @@ LinePatternPos LineAtlas::addDash(const std::vector<float> &dasharray, bool roun
nextRow += dashheight;
dirty = true;
- bind(store);
return position;
-};
+}
-void LineAtlas::upload(gl::ObjectStore& store) {
+void LineAtlas::upload(gl::ObjectStore& store, gl::Config& config, uint32_t unit) {
if (dirty) {
- bind(store);
+ bind(store, config, unit);
}
}
-void LineAtlas::bind(gl::ObjectStore& store) {
+void LineAtlas::bind(gl::ObjectStore& store, gl::Config& config, uint32_t unit) {
bool first = false;
if (!texture) {
texture = store.createTexture();
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
+ config.activeTexture = unit;
+ config.texture[unit] = *texture;
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
first = true;
- } else {
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
+ } else if (config.texture[unit] != *texture) {
+ config.activeTexture = unit;
+ config.texture[unit] = *texture;
}
if (dirty) {
+ config.activeTexture = unit;
if (first) {
MBGL_CHECK_ERROR(glTexImage2D(
GL_TEXTURE_2D, // GLenum target
@@ -171,4 +172,6 @@ void LineAtlas::bind(gl::ObjectStore& store) {
dirty = false;
}
-};
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/geometry/line_atlas.hpp b/src/mbgl/geometry/line_atlas.hpp
index 0ca5e95a23..1e6c0ac84e 100644
--- a/src/mbgl/geometry/line_atlas.hpp
+++ b/src/mbgl/geometry/line_atlas.hpp
@@ -9,6 +9,10 @@
namespace mbgl {
+namespace gl {
+class Config;
+} // namespace gl
+
typedef struct {
float width;
float height;
@@ -21,14 +25,14 @@ public:
~LineAtlas();
// Binds the atlas texture to the GPU, and uploads data if it is out of date.
- void bind(gl::ObjectStore&);
+ void bind(gl::ObjectStore&, gl::Config&, uint32_t unit);
// Uploads the texture to the GPU to be available when we need it. This is a lazy operation;
// the texture is only bound when the data is out of date (=dirty).
- void upload(gl::ObjectStore&);
+ void upload(gl::ObjectStore&, gl::Config&, uint32_t unit);
- LinePatternPos getDashPosition(const std::vector<float>&, bool, gl::ObjectStore&);
- LinePatternPos addDash(const std::vector<float> &dasharray, bool round, gl::ObjectStore&);
+ LinePatternPos getDashPosition(const std::vector<float>&, bool);
+ LinePatternPos addDash(const std::vector<float>& dasharray, bool round);
const GLsizei width;
const GLsizei height;
diff --git a/src/mbgl/geometry/line_buffer.cpp b/src/mbgl/geometry/line_buffer.cpp
index 3d979a2a45..7d2e2eb9a2 100644
--- a/src/mbgl/geometry/line_buffer.cpp
+++ b/src/mbgl/geometry/line_buffer.cpp
@@ -3,7 +3,7 @@
#include <cmath>
-using namespace mbgl;
+namespace mbgl {
GLsizei LineVertexBuffer::add(vertex_type x, vertex_type y, float ex, float ey, bool tx, bool ty, int8_t dir, int32_t linesofar) {
GLsizei idx = index();
@@ -34,3 +34,5 @@ GLsizei LineVertexBuffer::add(vertex_type x, vertex_type y, float ex, float ey,
return idx;
}
+
+} // namespace mbgl
diff --git a/src/mbgl/geometry/static_vertex_buffer.cpp b/src/mbgl/geometry/static_vertex_buffer.cpp
index 254b01b6b6..c66b194748 100644
--- a/src/mbgl/geometry/static_vertex_buffer.cpp
+++ b/src/mbgl/geometry/static_vertex_buffer.cpp
@@ -3,11 +3,21 @@
namespace mbgl {
-StaticVertexBuffer::StaticVertexBuffer(std::initializer_list<std::pair<int16_t, int16_t>> init) {
+StaticVertexBuffer::StaticVertexBuffer(std::initializer_list<std::array<VertexType, 2>> init) {
for (const auto& vertex : init) {
- vertex_type *vertices = static_cast<vertex_type *>(addElement());
- vertices[0] = vertex.first;
- vertices[1] = vertex.second;
+ VertexType* vertices = static_cast<VertexType*>(addElement());
+ vertices[0] = std::get<0>(vertex);
+ vertices[1] = std::get<1>(vertex);
+ }
+}
+
+StaticRasterVertexBuffer::StaticRasterVertexBuffer(std::initializer_list<std::array<VertexType, 4>> init) {
+ for (const auto& vertex : init) {
+ VertexType* vertices = static_cast<VertexType*>(addElement());
+ vertices[0] = std::get<0>(vertex);
+ vertices[1] = std::get<1>(vertex);
+ vertices[2] = std::get<2>(vertex);
+ vertices[3] = std::get<3>(vertex);
}
}
diff --git a/src/mbgl/geometry/static_vertex_buffer.hpp b/src/mbgl/geometry/static_vertex_buffer.hpp
index 79f6117cbc..2e738afc98 100644
--- a/src/mbgl/geometry/static_vertex_buffer.hpp
+++ b/src/mbgl/geometry/static_vertex_buffer.hpp
@@ -2,10 +2,8 @@
#include <mbgl/geometry/buffer.hpp>
-#include <vector>
-#include <cstddef>
+#include <array>
#include <cstdint>
-#include <cmath>
namespace mbgl {
@@ -15,9 +13,18 @@ class StaticVertexBuffer : public Buffer<
32 // default length
> {
public:
- typedef int16_t vertex_type;
+ using VertexType = int16_t;
+ StaticVertexBuffer(std::initializer_list<std::array<VertexType, 2>>);
+};
- StaticVertexBuffer(std::initializer_list<std::pair<int16_t, int16_t>> init);
+class StaticRasterVertexBuffer : public Buffer<
+ 8, // bytes per vertex (4 * signed short == 8 bytes)
+ GL_ARRAY_BUFFER,
+ 32 // default length
+> {
+public:
+ using VertexType = int16_t;
+ StaticRasterVertexBuffer(std::initializer_list<std::array<VertexType, 4>>);
};
} // namespace mbgl
diff --git a/src/mbgl/geometry/text_buffer.cpp b/src/mbgl/geometry/text_buffer.cpp
index 1aa65146a4..382e87324d 100644
--- a/src/mbgl/geometry/text_buffer.cpp
+++ b/src/mbgl/geometry/text_buffer.cpp
@@ -6,7 +6,7 @@
namespace mbgl {
-size_t TextVertexBuffer::add(int16_t x, int16_t y, float ox, float oy, uint16_t tx, uint16_t ty, float minzoom, float maxzoom, float labelminzoom) {
+size_t TextVertexBuffer::add(int16_t x, int16_t y, float ox, float oy, uint16_t tx, uint16_t ty, float minzoom, float maxzoom, float labelminzoom, uint8_t labelangle) {
const size_t idx = index();
void *data = addElement();
@@ -21,6 +21,7 @@ size_t TextVertexBuffer::add(int16_t x, int16_t y, float ox, float oy, uint16_t
ubytes[8] /* tex */ = tx / 4;
ubytes[9] /* tex */ = ty / 4;
ubytes[10] /* labelminzoom */ = labelminzoom * 10;
+ ubytes[11] /* labelangle */ = labelangle;
// a_data2
ubytes[12] /* minzoom */ = minzoom * 10; // 1/10 zoom levels: z16 == 160.
diff --git a/src/mbgl/geometry/text_buffer.hpp b/src/mbgl/geometry/text_buffer.hpp
index 8d7859fde2..c6b632c67e 100644
--- a/src/mbgl/geometry/text_buffer.hpp
+++ b/src/mbgl/geometry/text_buffer.hpp
@@ -13,7 +13,7 @@ class TextVertexBuffer : public Buffer <
public:
typedef int16_t vertex_type;
- size_t add(int16_t x, int16_t y, float ox, float oy, uint16_t tx, uint16_t ty, float minzoom, float maxzoom, float labelminzoom);
+ size_t add(int16_t x, int16_t y, float ox, float oy, uint16_t tx, uint16_t ty, float minzoom, float maxzoom, float labelminzoom, uint8_t labelangle);
};
diff --git a/src/mbgl/geometry/vao.cpp b/src/mbgl/geometry/vao.cpp
index 46f10cb48c..30f5484896 100644
--- a/src/mbgl/geometry/vao.cpp
+++ b/src/mbgl/geometry/vao.cpp
@@ -13,8 +13,7 @@ void VertexArrayObject::Unbind() {
VertexArrayObject::VertexArrayObject() {
}
-VertexArrayObject::~VertexArrayObject() {
-}
+VertexArrayObject::~VertexArrayObject() = default;
void VertexArrayObject::bindVertexArrayObject(gl::ObjectStore& store) {
if (!gl::GenVertexArrays || !gl::BindVertexArray) {
@@ -32,7 +31,7 @@ void VertexArrayObject::bindVertexArrayObject(gl::ObjectStore& store) {
MBGL_CHECK_ERROR(gl::BindVertexArray(*vao));
}
-void VertexArrayObject::verifyBinding(Shader &shader, GLuint vertexBuffer, GLuint elementsBuffer,
+void VertexArrayObject::verifyBinding(Shader& shader, GLuint vertexBuffer, GLuint elementsBuffer,
GLbyte *offset) {
if (bound_shader != shader.getID()) {
throw std::runtime_error(std::string("trying to rebind VAO to another shader from " +
diff --git a/src/mbgl/geometry/vao.hpp b/src/mbgl/geometry/vao.hpp
index 150a6badbd..aa0a72ec59 100644
--- a/src/mbgl/geometry/vao.hpp
+++ b/src/mbgl/geometry/vao.hpp
@@ -10,8 +10,6 @@
namespace mbgl {
-class Shader;
-
class VertexArrayObject : public util::noncopyable {
public:
static void Unbind();
@@ -19,8 +17,8 @@ public:
VertexArrayObject();
~VertexArrayObject();
- template <typename Shader, typename VertexBuffer>
- inline void bind(Shader& shader, VertexBuffer &vertexBuffer, GLbyte *offset, gl::ObjectStore& store) {
+ template <typename VertexBuffer>
+ void bind(Shader& shader, VertexBuffer& vertexBuffer, GLbyte* offset, gl::ObjectStore& store) {
bindVertexArrayObject(store);
if (bound_shader == 0) {
vertexBuffer.bind(store);
@@ -33,8 +31,8 @@ public:
}
}
- template <typename Shader, typename VertexBuffer, typename ElementsBuffer>
- inline void bind(Shader& shader, VertexBuffer &vertexBuffer, ElementsBuffer &elementsBuffer, GLbyte *offset, gl::ObjectStore& store) {
+ template <typename VertexBuffer, typename ElementsBuffer>
+ void bind(Shader& shader, VertexBuffer& vertexBuffer, ElementsBuffer& elementsBuffer, GLbyte* offset, gl::ObjectStore& store) {
bindVertexArrayObject(store);
if (bound_shader == 0) {
vertexBuffer.bind(store);
@@ -62,10 +60,10 @@ private:
// For debug reasons, we're storing the bind information so that we can
// detect errors and report
GLuint bound_shader = 0;
- const char *bound_shader_name = "";
+ const char* bound_shader_name = "";
GLuint bound_vertex_buffer = 0;
GLuint bound_elements_buffer = 0;
- GLbyte *bound_offset = 0;
+ GLbyte *bound_offset = nullptr;
};
} // namespace mbgl
diff --git a/src/mbgl/gl/gl.cpp b/src/mbgl/gl/gl.cpp
index 48f00ec177..7747717c63 100644
--- a/src/mbgl/gl/gl.cpp
+++ b/src/mbgl/gl/gl.cpp
@@ -121,7 +121,7 @@ namespace mbgl {
void mbx_trapExtension(const char *, GLenum, GLuint, GLsizei, const GLchar *) { }
void mbx_trapExtension(const char *, GLDEBUGPROC, const void *) { }
void mbx_trapExtension(const char *, GLuint, GLuint, GLuint, GLuint, GLint, const char *, const void*) { }
-
+
void mbx_trapExtension(const char *name, GLuint array) {
if(strncasecmp(name, "glBindVertexArray", 17) == 0) {
currentVertexArray = array;
@@ -188,7 +188,7 @@ void mbx_glBufferData(GLenum target,
}
std::cout << "GL glBufferData: " << currentBinding << " using " << bufferBindingToSizeMap[currentBinding] << " bytes current total " << currentUsedBufferBytes << " high water mark " << largestAmountUsedSoFar << "\n";
lock.unlock();
-
+
glBufferData(target, size, data, usage);
}
diff --git a/src/mbgl/gl/gl_config.cpp b/src/mbgl/gl/gl_config.cpp
index c3c6601e43..9031c3d34f 100644
--- a/src/mbgl/gl/gl_config.cpp
+++ b/src/mbgl/gl/gl_config.cpp
@@ -13,13 +13,15 @@ const DepthTest::Type DepthTest::Default = GL_FALSE;
const DepthFunc::Type DepthFunc::Default = GL_LEQUAL;
const Blend::Type Blend::Default = GL_TRUE;
const BlendFunc::Type BlendFunc::Default = { GL_ONE, GL_ONE_MINUS_SRC_ALPHA };
+const BlendColor::Type BlendColor::Default = { 0, 0, 0, 0 };
const ColorMask::Type ColorMask::Default = { GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE };
const ClearDepth::Type ClearDepth::Default = 1;
const ClearColor::Type ClearColor::Default = { 0, 0, 0, 0 };
const ClearStencil::Type ClearStencil::Default = 0;
const Program::Type Program::Default = 0;
const LineWidth::Type LineWidth::Default = 1;
-const ActiveTexture::Type ActiveTexture::Default = GL_TEXTURE0;
+const ActiveTexture::Type ActiveTexture::Default = 0;
+const BindTexture::Type BindTexture::Default = 0;
#ifndef GL_ES_VERSION_2_0
const PixelZoom::Type PixelZoom::Default = { 1, 1 };
diff --git a/src/mbgl/gl/gl_config.hpp b/src/mbgl/gl/gl_config.hpp
index 66f4406530..41bee8fab7 100644
--- a/src/mbgl/gl/gl_config.hpp
+++ b/src/mbgl/gl/gl_config.hpp
@@ -13,28 +13,30 @@ template <typename T>
class Value {
public:
void operator=(const typename T::Type& value) {
- if (dirty || current != value) {
+ if (*this != value) {
dirty = false;
current = value;
T::Set(current);
}
}
+ bool operator!=(const typename T::Type& value) const {
+ return dirty || current != value;
+ }
+
void reset() {
- dirty = true;
- current = T::Default;
- T::Set(current);
+ *this = T::Default;
}
void setDirty() {
dirty = true;
}
- typename T::Type getCurrent() {
+ typename T::Type getCurrent() const {
return current;
}
- bool getDirty() {
+ bool getDirty() const {
return dirty;
}
@@ -56,6 +58,7 @@ public:
depthFunc.reset();
blend.reset();
blendFunc.reset();
+ blendColor.reset();
colorMask.reset();
clearDepth.reset();
clearColor.reset();
@@ -80,6 +83,7 @@ public:
depthFunc.setDirty();
blend.setDirty();
blendFunc.setDirty();
+ blendColor.setDirty();
colorMask.setDirty();
clearDepth.setDirty();
clearColor.setDirty();
@@ -103,6 +107,7 @@ public:
Value<DepthFunc> depthFunc;
Value<Blend> blend;
Value<BlendFunc> blendFunc;
+ Value<BlendColor> blendColor;
Value<ColorMask> colorMask;
Value<ClearDepth> clearDepth;
Value<ClearColor> clearColor;
@@ -114,6 +119,7 @@ public:
Value<PixelZoom> pixelZoom;
Value<RasterPos> rasterPos;
#endif // GL_ES_VERSION_2_0
+ std::array<Value<BindTexture>, 2> texture;
};
} // namespace gl
diff --git a/src/mbgl/gl/object_store.cpp b/src/mbgl/gl/object_store.cpp
index 3072296a1e..4139854f61 100644
--- a/src/mbgl/gl/object_store.cpp
+++ b/src/mbgl/gl/object_store.cpp
@@ -22,7 +22,11 @@ void BufferDeleter::operator()(GLuint id) const {
void TextureDeleter::operator()(GLuint id) const {
assert(store);
- store->abandonedTextures.push_back(id);
+ if (store->pooledTextures.size() >= TextureMax) {
+ store->abandonedTextures.push_back(id);
+ } else {
+ store->pooledTextures.push_back(id);
+ }
}
void VAODeleter::operator()(GLuint id) const {
@@ -30,17 +34,8 @@ void VAODeleter::operator()(GLuint id) const {
store->abandonedVAOs.push_back(id);
}
-void TexturePoolDeleter::operator()(ObjectPool ids) const {
- assert(store);
- for (GLuint& id : ids) {
- if (id) {
- store->abandonedTextures.push_back(id);
- id = 0;
- };
- }
-}
-
ObjectStore::~ObjectStore() {
+ assert(pooledTextures.empty());
assert(abandonedPrograms.empty());
assert(abandonedShaders.empty());
assert(abandonedBuffers.empty());
@@ -48,6 +43,12 @@ ObjectStore::~ObjectStore() {
assert(abandonedVAOs.empty());
}
+void ObjectStore::reset() {
+ std::copy(pooledTextures.begin(), pooledTextures.end(), std::back_inserter(abandonedTextures));
+ pooledTextures.resize(0);
+ performCleanup();
+}
+
void ObjectStore::performCleanup() {
for (GLuint id : abandonedPrograms) {
MBGL_CHECK_ERROR(glDeleteProgram(id));
diff --git a/src/mbgl/gl/object_store.hpp b/src/mbgl/gl/object_store.hpp
index 3ae1b6e2fe..96bb8008f1 100644
--- a/src/mbgl/gl/object_store.hpp
+++ b/src/mbgl/gl/object_store.hpp
@@ -5,9 +5,7 @@
#include <unique_resource.hpp>
-#include <array>
#include <algorithm>
-#include <cassert>
#include <memory>
#include <vector>
@@ -43,19 +41,11 @@ struct VAODeleter {
void operator()(GLuint) const;
};
-using ObjectPool = std::array<GLuint, TextureMax>;
-
-struct TexturePoolDeleter {
- ObjectStore* store;
- void operator()(ObjectPool ids) const;
-};
-
using UniqueProgram = std_experimental::unique_resource<GLuint, ProgramDeleter>;
using UniqueShader = std_experimental::unique_resource<GLuint, ShaderDeleter>;
using UniqueBuffer = std_experimental::unique_resource<GLuint, BufferDeleter>;
using UniqueTexture = std_experimental::unique_resource<GLuint, TextureDeleter>;
using UniqueVAO = std_experimental::unique_resource<GLuint, VAODeleter>;
-using UniqueTexturePool = std_experimental::unique_resource<ObjectPool, TexturePoolDeleter>;
class ObjectStore : private util::noncopyable {
public:
@@ -76,8 +66,13 @@ public:
}
UniqueTexture createTexture() {
- GLuint id = 0;
- MBGL_CHECK_ERROR(glGenTextures(1, &id));
+ if (pooledTextures.empty()) {
+ pooledTextures.resize(TextureMax);
+ MBGL_CHECK_ERROR(glGenTextures(TextureMax, pooledTextures.data()));
+ }
+
+ GLuint id = pooledTextures.back();
+ pooledTextures.pop_back();
return UniqueTexture { std::move(id), { this } };
}
@@ -87,19 +82,17 @@ public:
return UniqueVAO { std::move(id), { this } };
}
- UniqueTexturePool createTexturePool() {
- ObjectPool ids;
- MBGL_CHECK_ERROR(glGenTextures(TextureMax, ids.data()));
- assert(ids.size() == size_t(TextureMax));
- return UniqueTexturePool { std::move(ids), { this } };
- }
-
// Actually remove the objects we marked as abandoned with the above methods.
// Only call this while the OpenGL context is exclusive to this thread.
void performCleanup();
+ // Drain pools and remove abandoned objects, in preparation for destroying the store.
+ // Only call this while the OpenGL context is exclusive to this thread.
+ void reset();
+
bool empty() const {
- return abandonedPrograms.empty()
+ return pooledTextures.empty()
+ && abandonedPrograms.empty()
&& abandonedShaders.empty()
&& abandonedBuffers.empty()
&& abandonedTextures.empty()
@@ -112,7 +105,8 @@ private:
friend BufferDeleter;
friend TextureDeleter;
friend VAODeleter;
- friend TexturePoolDeleter;
+
+ std::vector<GLuint> pooledTextures;
std::vector<GLuint> abandonedPrograms;
std::vector<GLuint> abandonedShaders;
diff --git a/src/mbgl/gl/texture_pool.cpp b/src/mbgl/gl/texture_pool.cpp
deleted file mode 100644
index c4984b0186..0000000000
--- a/src/mbgl/gl/texture_pool.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-#include <mbgl/gl/texture_pool.hpp>
-#include <mbgl/gl/object_store.hpp>
-
-#include <algorithm>
-#include <vector>
-
-namespace mbgl {
-namespace gl {
-
-class TexturePool::Impl : private util::noncopyable {
-public:
- class Pool : private util::noncopyable {
- public:
- Pool(gl::ObjectStore& store) : pool(store.createTexturePool()), availableIDs(gl::TextureMax) {
- std::copy(pool.get().begin(), pool.get().end(), availableIDs.begin());
- }
-
- Pool(Pool&& o) : pool(std::move(o.pool)), availableIDs(std::move(o.availableIDs)) {}
- Pool& operator=(Pool&& o) { pool = std::move(o.pool); availableIDs = std::move(o.availableIDs); return *this; }
-
- gl::UniqueTexturePool pool;
- std::vector<GLuint> availableIDs;
- };
-
- GLuint acquireTexture(gl::ObjectStore& store) {
- auto nextAvailableID = [](auto& pool_) {
- auto it = pool_.availableIDs.begin();
- GLuint id = *it;
- pool_.availableIDs.erase(it);
- return id;
- };
-
- for (auto& pool : pools) {
- if (pool.availableIDs.empty()) continue;
- return nextAvailableID(pool);
- }
-
- // All texture IDs are in use.
- pools.emplace_back(Pool { store });
- return nextAvailableID(pools.back());
- }
-
- void releaseTexture(GLuint id) {
- for (auto it = pools.begin(); it != pools.end(); ++it) {
- if (std::find(it->pool.get().begin(), it->pool.get().end(), id) != it->pool.get().end()) {
- it->availableIDs.push_back(id);
- if (GLsizei(it->availableIDs.size()) == gl::TextureMax) {
- pools.erase(it);
- }
- return;
- }
- }
- }
-
-private:
- std::vector<Pool> pools;
-};
-
-void TextureReleaser::operator()(GLuint id) const {
- assert(pool);
- pool->impl->releaseTexture(id);
-}
-
-TexturePool::TexturePool() : impl(std::make_unique<Impl>()) {
-}
-
-TexturePool::~TexturePool() {
-}
-
-PooledTexture TexturePool::acquireTexture(gl::ObjectStore& store) {
- return PooledTexture { impl->acquireTexture(store) , { this } };
-}
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/gl/texture_pool.hpp b/src/mbgl/gl/texture_pool.hpp
deleted file mode 100644
index 1cdcdf220c..0000000000
--- a/src/mbgl/gl/texture_pool.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#pragma once
-
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/gl/gl.hpp>
-#include <mbgl/gl/object_store.hpp>
-
-#include <unique_resource.hpp>
-
-#include <memory>
-
-namespace mbgl {
-namespace gl {
-
-class TexturePool;
-
-struct TextureReleaser {
- TexturePool* pool;
- void operator()(GLuint) const;
-};
-
-using PooledTexture = std_experimental::unique_resource<GLuint, TextureReleaser>;
-
-class TexturePool : private util::noncopyable {
-public:
- TexturePool();
- ~TexturePool();
-
- PooledTexture acquireTexture(gl::ObjectStore&);
-
-private:
- friend TextureReleaser;
-
- class Impl;
- const std::unique_ptr<Impl> impl;
-};
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/map/camera.cpp b/src/mbgl/map/camera.cpp
deleted file mode 100644
index 4a45e904f8..0000000000
--- a/src/mbgl/map/camera.cpp
+++ /dev/null
@@ -1 +0,0 @@
-#include <mbgl/map/camera.hpp>
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 24c39fe243..659832dc77 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -5,6 +5,7 @@
#include <mbgl/map/transform_state.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/style/style.hpp>
+#include <mbgl/style/source.hpp>
#include <mbgl/style/layer.hpp>
#include <mbgl/style/observer.hpp>
#include <mbgl/style/transition_options.hpp>
@@ -15,7 +16,6 @@
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/gl/object_store.hpp>
-#include <mbgl/gl/texture_pool.hpp>
#include <mbgl/util/projection.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/exception.hpp>
@@ -37,7 +37,7 @@ class Map::Impl : public style::Observer {
public:
Impl(View&, FileSource&, MapMode, GLContextMode, ConstrainMode, ViewportMode);
- void onResourceLoaded() override;
+ void onNeedsRepaint() override;
void onResourceError(std::exception_ptr) override;
void update();
@@ -62,7 +62,6 @@ public:
util::AsyncTask asyncUpdate;
std::unique_ptr<AnnotationManager> annotationManager;
- std::unique_ptr<gl::TexturePool> texturePool;
std::unique_ptr<Painter> painter;
std::unique_ptr<Style> style;
@@ -98,8 +97,7 @@ Map::Impl::Impl(View& view_,
contextMode(contextMode_),
pixelRatio(view.getPixelRatio()),
asyncUpdate([this] { update(); }),
- annotationManager(std::make_unique<AnnotationManager>(pixelRatio)),
- texturePool(std::make_unique<gl::TexturePool>()) {
+ annotationManager(std::make_unique<AnnotationManager>(pixelRatio)) {
}
Map::~Map() {
@@ -108,13 +106,11 @@ Map::~Map() {
impl->styleRequest = nullptr;
// Explicit resets currently necessary because these abandon resources that need to be
- // cleaned up by store.performCleanup();
+ // cleaned up by store.reset();
impl->style.reset();
impl->painter.reset();
- impl->texturePool.reset();
impl->annotationManager.reset();
-
- impl->store.performCleanup();
+ impl->store.reset();
impl->view.deactivate();
}
@@ -210,11 +206,15 @@ void Map::Impl::update() {
// - Hint style sources to notify when all its tiles are loaded;
timePoint = Clock::now();
- if (style->loaded && updateFlags & Update::Annotations) {
+ if (style->loaded && updateFlags & Update::AnnotationStyle) {
annotationManager->updateStyle(*style);
updateFlags |= Update::Classes;
}
+ if (updateFlags & Update::AnnotationData) {
+ annotationManager->updateData();
+ }
+
if (updateFlags & Update::Classes) {
style->cascade(timePoint, mode);
}
@@ -229,7 +229,6 @@ void Map::Impl::update() {
transform.getState(),
style->workers,
fileSource,
- *texturePool,
style->shouldReparsePartialTiles,
mode,
*annotationManager,
@@ -337,7 +336,7 @@ void Map::Impl::loadStyleJSON(const std::string& json) {
// force style cascade, causing all pending transitions to complete.
style->cascade(Clock::now(), mode);
- updateFlags |= Update::Classes | Update::RecalculateStyle | Update::Annotations;
+ updateFlags |= Update::Classes | Update::RecalculateStyle | Update::AnnotationStyle;
asyncUpdate.send();
}
@@ -378,7 +377,7 @@ bool Map::isPanning() const {
}
#pragma mark -
-
+
CameraOptions Map::getCameraOptions(optional<EdgeInsets> padding) const {
return impl->transform.getCameraOptions(padding);
}
@@ -691,18 +690,17 @@ double Map::getTopOffsetPixelsForAnnotationIcon(const std::string& name) {
AnnotationID Map::addAnnotation(const Annotation& annotation) {
auto result = impl->annotationManager->addAnnotation(annotation, getMaxZoom());
- update(Update::Annotations);
+ update(Update::AnnotationStyle | Update::AnnotationData);
return result;
}
void Map::updateAnnotation(AnnotationID id, const Annotation& annotation) {
- impl->annotationManager->updateAnnotation(id, annotation, getMaxZoom());
- update(Update::Annotations);
+ update(impl->annotationManager->updateAnnotation(id, annotation, getMaxZoom()));
}
void Map::removeAnnotation(AnnotationID annotation) {
impl->annotationManager->removeAnnotation(annotation);
- update(Update::Annotations);
+ update(Update::AnnotationStyle | Update::AnnotationData);
}
AnnotationIDs Map::getPointAnnotationsInBounds(const LatLngBounds& bounds) {
@@ -739,6 +737,22 @@ std::vector<Feature> Map::queryRenderedFeatures(const ScreenBox& box, const opti
#pragma mark - Style API
+style::Source* Map::getSource(const std::string& sourceID) {
+ return impl->style ? impl->style->getSource(sourceID) : nullptr;
+}
+
+void Map::addSource(std::unique_ptr<style::Source> source) {
+ impl->style->addSource(std::move(source));
+}
+
+void Map::removeSource(const std::string& sourceID) {
+ impl->style->removeSource(sourceID);
+}
+
+style::Layer* Map::getLayer(const std::string& layerID) {
+ return impl->style ? impl->style->getLayer(layerID) : nullptr;
+}
+
void Map::addLayer(std::unique_ptr<Layer> layer, const optional<std::string>& before) {
impl->view.activate();
@@ -770,14 +784,14 @@ void Map::cycleDebugOptions() {
#ifndef GL_ES_VERSION_2_0
if (impl->debugOptions & MapDebugOptions::StencilClip)
impl->debugOptions = MapDebugOptions::NoDebug;
- else if (impl->debugOptions & MapDebugOptions::Wireframe)
+ else if (impl->debugOptions & MapDebugOptions::Overdraw)
impl->debugOptions = MapDebugOptions::StencilClip;
#else
- if (impl->debugOptions & MapDebugOptions::Wireframe)
+ if (impl->debugOptions & MapDebugOptions::Overdraw)
impl->debugOptions = MapDebugOptions::NoDebug;
#endif // GL_ES_VERSION_2_0
else if (impl->debugOptions & MapDebugOptions::Collision)
- impl->debugOptions = MapDebugOptions::Collision | MapDebugOptions::Wireframe;
+ impl->debugOptions = MapDebugOptions::Overdraw;
else if (impl->debugOptions & MapDebugOptions::Timestamps)
impl->debugOptions = impl->debugOptions | MapDebugOptions::Collision;
else if (impl->debugOptions & MapDebugOptions::ParseStatus)
@@ -839,7 +853,7 @@ void Map::onLowMemory() {
impl->view.invalidate();
}
-void Map::Impl::onResourceLoaded() {
+void Map::Impl::onNeedsRepaint() {
updateFlags |= Update::Repaint;
asyncUpdate.send();
}
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index bf95dd0714..41fc36ce27 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -14,7 +14,7 @@
#include <cstdio>
#include <cmath>
-using namespace mbgl;
+namespace mbgl {
/** Converts the given angle (in radians) to be numerically close to the anchor angle, allowing it to be interpolated properly without sudden jumps. */
static double _normalizeAngle(double angle, double anchorAngle)
@@ -117,24 +117,24 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
ScreenCoordinate center = getScreenCoordinate(padding);
center.y = state.height - center.y;
-
+
// Constrain camera options.
zoom = util::clamp(zoom, state.getMinZoom(), state.getMaxZoom());
const double scale = state.zoomScale(zoom);
pitch = util::clamp(pitch, 0., util::PITCH_MAX);
-
+
Update update = state.getZoom() == zoom ? Update::Repaint : Update::RecalculateStyle;
-
+
// Minimize rotation by taking the shorter path around the circle.
angle = _normalizeAngle(angle, state.angle);
state.angle = _normalizeAngle(state.angle, angle);
Duration duration = animation.duration ? *animation.duration : Duration::zero();
-
+
const double startWorldSize = state.worldSize();
state.Bc = startWorldSize / util::DEGREES_MAX;
state.Cc = startWorldSize / util::M2PI;
-
+
const double startScale = state.scale;
const double startAngle = state.angle;
const double startPitch = state.pitch;
@@ -147,14 +147,14 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
LatLng frameLatLng = state.unproject(framePoint, startWorldSize);
double frameScale = util::interpolate(startScale, scale, t);
state.setLatLngZoom(frameLatLng, state.scaleZoom(frameScale));
-
+
if (angle != startAngle) {
state.angle = util::wrap(util::interpolate(startAngle, angle, t), -M_PI, M_PI);
}
if (pitch != startPitch) {
state.pitch = util::interpolate(startPitch, pitch, t);
}
-
+
if (padding) {
state.moveLatLng(frameLatLng, center);
}
@@ -163,11 +163,11 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
}
/** This method implements an “optimal path” animation, as detailed in:
-
+
Van Wijk, Jarke J.; Nuij, Wim A. A. “Smooth and efficient zooming and
panning.” INFOVIS ’03. pp. 15–22.
<https://www.win.tue.nl/~vanwijk/zoompan.pdf#page=5>.
-
+
Where applicable, local variable documentation begins with the associated
variable or function in van Wijk (2003). */
void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &animation) {
@@ -179,7 +179,7 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
if (!latLng || std::isnan(zoom)) {
return;
}
-
+
// Determine endpoints.
EdgeInsets padding;
if (camera.padding) padding = *camera.padding;
@@ -191,19 +191,19 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
ScreenCoordinate center = getScreenCoordinate(padding);
center.y = state.height - center.y;
-
+
// Constrain camera options.
zoom = util::clamp(zoom, state.getMinZoom(), state.getMaxZoom());
pitch = util::clamp(pitch, 0., util::PITCH_MAX);
-
+
// Minimize rotation by taking the shorter path around the circle.
angle = _normalizeAngle(angle, state.angle);
state.angle = _normalizeAngle(state.angle, angle);
-
+
const double startZoom = state.scaleZoom(state.scale);
const double startAngle = state.angle;
const double startPitch = state.pitch;
-
+
/// w₀: Initial visible span, measured in pixels at the initial scale.
/// Known henceforth as a <i>screenful</i>.
double w0 = padding ? std::max(state.width, state.height)
@@ -215,11 +215,11 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
/// Length of the flight path as projected onto the ground plane, measured
/// in pixels from the world image origin at the initial scale.
double u1 = ::hypot((endPoint - startPoint).x, (endPoint - startPoint).y);
-
+
/** ρ: The relative amount of zooming that takes place along the flight
path. A high value maximizes zooming for an exaggerated animation, while
a low value minimizes zooming for something closer to easeTo().
-
+
1.42 is the average value selected by participants in the user study in
van Wijk (2003). A value of 6<sup>¼</sup> would be equivalent to the
root mean squared average velocity, V<sub>RMS</sub>. A value of 1 would
@@ -235,16 +235,16 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
}
/// ρ²
double rho2 = rho * rho;
-
+
/** rᵢ: Returns the zoom-out factor at one end of the animation.
-
+
@param i 0 for the ascent or 1 for the descent. */
auto r = [=](double i) {
/// bᵢ
double b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);
return std::log(std::sqrt(b * b + 1) - b);
};
-
+
// When u₀ = u₁, the optimal path doesn’t require both ascent and descent.
bool isClose = std::abs(u1) < 0.000001;
// Perform a more or less instantaneous transition if the path is too short.
@@ -252,12 +252,12 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
easeTo(camera, animation);
return;
}
-
+
/// r₀: Zoom-out factor during ascent.
double r0 = r(0);
/** w(s): Returns the visible span on the ground, measured in pixels with
respect to the initial scale.
-
+
Assumes an angular field of view of 2 arctan ½ ≈ 53°. */
auto w = [=](double s) {
return (isClose ? std::exp((w1 < w0 ? -1 : 1) * rho * s)
@@ -273,7 +273,7 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
/// S: Total length of the flight path, measured in ρ-screenfuls.
double S = (isClose ? (std::abs(std::log(w1 / w0)) / rho)
: ((r(1) - r0) / rho));
-
+
Duration duration;
if (animation.duration) {
duration = *animation.duration;
@@ -290,36 +290,36 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
jumpTo(camera);
return;
}
-
+
const double startWorldSize = state.worldSize();
state.Bc = startWorldSize / util::DEGREES_MAX;
state.Cc = startWorldSize / util::M2PI;
-
+
state.panning = true;
state.scaling = true;
state.rotating = angle != startAngle;
-
+
startTransition(camera, animation, [=](double k) {
/// s: The distance traveled along the flight path, measured in
/// ρ-screenfuls.
double s = k * S;
double us = u(s);
-
+
// Calculate the current point and zoom level along the flight path.
Point<double> framePoint = util::interpolate(startPoint, endPoint, us);
double frameZoom = startZoom + state.scaleZoom(1 / w(s));
-
+
// Convert to geographic coordinates and set the new viewpoint.
LatLng frameLatLng = state.unproject(framePoint, startWorldSize);
state.setLatLngZoom(frameLatLng, frameZoom);
-
+
if (angle != startAngle) {
state.angle = util::wrap(util::interpolate(startAngle, angle, k), -M_PI, M_PI);
}
if (pitch != startPitch) {
state.pitch = util::interpolate(startPitch, pitch, k);
}
-
+
if (padding) {
state.moveLatLng(frameLatLng, center);
}
@@ -474,7 +474,7 @@ void Transform::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate&
center.x = first.x + std::cos(rotateAngle) * heightOffset;
center.y = first.y + std::sin(rotateAngle) * heightOffset;
}
-
+
CameraOptions camera;
camera.angle = state.angle + util::angle_between(first - center, second - center);
easeTo(camera, duration);
@@ -561,7 +561,7 @@ void Transform::startTransition(const CameraOptions& camera,
if (transitionFinishFn) {
transitionFinishFn();
}
-
+
bool isAnimated = duration != Duration::zero();
if (callback) {
callback(isAnimated ? MapChangeRegionWillChangeAnimated : MapChangeRegionWillChange);
@@ -584,12 +584,12 @@ void Transform::startTransition(const CameraOptions& camera,
if (t >= 1.0) {
result = frame(1.0);
} else {
- util::UnitBezier ease = animation.easing ? *animation.easing : util::UnitBezier(0, 0, 0.25, 1);
+ util::UnitBezier ease = animation.easing ? *animation.easing : util::DEFAULT_TRANSITION_EASE;
result = frame(ease.solve(t, 0.001));
}
-
+
if (anchor) state.moveLatLng(anchorLatLng, *anchor);
-
+
// At t = 1.0, a DidChangeAnimated notification should be sent from finish().
if (t < 1.0) {
if (animation.transitionFrameFn) {
@@ -620,7 +620,7 @@ void Transform::startTransition(const CameraOptions& camera,
callback(isAnimated ? MapChangeRegionDidChangeAnimated : MapChangeRegionDidChange);
}
};
-
+
if (!isAnimated) {
transitionFrameFn(Clock::now());
}
@@ -665,3 +665,5 @@ LatLng Transform::screenCoordinateToLatLng(const ScreenCoordinate& point) const
flippedPoint.y = state.height - flippedPoint.y;
return state.screenCoordinateToLatLng(flippedPoint).wrapped();
}
+
+} // namespace mbgl
diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp
index 904ed11392..abc301b1cb 100644
--- a/src/mbgl/map/transform.hpp
+++ b/src/mbgl/map/transform.hpp
@@ -28,7 +28,7 @@ public:
// Camera
/** Returns the current camera options. */
CameraOptions getCameraOptions(optional<EdgeInsets>) const;
-
+
/** Instantaneously, synchronously applies the given camera options. */
void jumpTo(const CameraOptions&);
/** Asynchronously transitions all specified camera options linearly along
@@ -40,7 +40,7 @@ public:
void flyTo(const CameraOptions&, const AnimationOptions& = {});
// Position
-
+
/** Pans the map by the given amount.
@param offset The distance to pan the map by, measured in pixels from
top to bottom and from left to right. */
@@ -157,7 +157,7 @@ public:
bool isRotating() const { return state.isRotating(); }
bool isScaling() const { return state.isScaling(); }
bool isPanning() const { return state.isPanning(); }
-
+
// Conversion and projection
ScreenCoordinate latLngToScreenCoordinate(const LatLng&) const;
LatLng screenCoordinateToLatLng(const ScreenCoordinate&) const;
diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp
index fab5991de8..eb66513626 100644
--- a/src/mbgl/map/transform_state.cpp
+++ b/src/mbgl/map/transform_state.cpp
@@ -21,8 +21,8 @@ void TransformState::matrixFor(mat4& matrix, const UnwrappedTileID& tileID) cons
matrix::identity(matrix);
matrix::translate(matrix, matrix,
- static_cast<int64_t>(tileID.canonical.x + tileID.wrap * tileScale) * s,
- static_cast<int64_t>(tileID.canonical.y) * s, 0);
+ int64_t(tileID.canonical.x + tileID.wrap * tileScale) * s,
+ int64_t(tileID.canonical.y) * s, 0);
matrix::scale(matrix, matrix, s / util::EXTENT, s / util::EXTENT, 1);
}
@@ -336,10 +336,10 @@ void TransformState::setLatLngZoom(const LatLng &latLng, double zoom) {
const double newWorldSize = newScale * util::tileSize;
Bc = newWorldSize / util::DEGREES_MAX;
Cc = newWorldSize / util::M2PI;
-
+
const double m = 1 - 1e-15;
const double f = util::clamp(std::sin(util::DEG2RAD * latLng.latitude), -m, m);
-
+
ScreenCoordinate point = {
-latLng.longitude * Bc,
0.5 * Cc * std::log((1 + f) / (1 - f)),
@@ -351,7 +351,7 @@ void TransformState::setScalePoint(const double newScale, const ScreenCoordinate
double constrainedScale = newScale;
ScreenCoordinate constrainedPoint = point;
constrain(constrainedScale, constrainedPoint.x, constrainedPoint.y);
-
+
scale = constrainedScale;
x = constrainedPoint.x;
y = constrainedPoint.y;
diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp
index 0489b69dd4..1e4b2054f7 100644
--- a/src/mbgl/map/transform_state.hpp
+++ b/src/mbgl/map/transform_state.hpp
@@ -72,6 +72,9 @@ public:
Point<double> project(const LatLng&) const;
LatLng unproject(const Point<double>&, double worldSize, LatLng::WrapMode = LatLng::Unwrapped) const;
+ double zoomScale(double zoom) const;
+ double scaleZoom(double scale) const;
+
private:
bool rotatedNorth() const;
void constrain(double& scale, double& x, double& y) const;
@@ -85,13 +88,11 @@ private:
// logical dimensions
uint16_t width = 0, height = 0;
- double zoomScale(double zoom) const;
- double scaleZoom(double scale) const;
double worldSize() const;
mat4 coordinatePointMatrix(double z) const;
mat4 getPixelMatrix() const;
-
+
/** Recenter the map so that the given coordinate is located at the given
point on screen. */
void moveLatLng(const LatLng&, const ScreenCoordinate&);
diff --git a/src/mbgl/platform/event.cpp b/src/mbgl/platform/event.cpp
new file mode 100644
index 0000000000..68d75a2941
--- /dev/null
+++ b/src/mbgl/platform/event.cpp
@@ -0,0 +1,34 @@
+#include <mbgl/platform/event.hpp>
+#include <mbgl/util/enum.hpp>
+
+namespace mbgl {
+
+MBGL_DEFINE_ENUM(EventSeverity, {
+ { EventSeverity::Debug, "DEBUG" },
+ { EventSeverity::Info, "INFO" },
+ { EventSeverity::Warning, "WARNING" },
+ { EventSeverity::Error, "ERROR" },
+ { EventSeverity(-1), "UNKNOWN" },
+});
+
+MBGL_DEFINE_ENUM(Event, {
+ { Event::General, "General" },
+ { Event::Setup, "Setup" },
+ { Event::Shader, "Shader" },
+ { Event::ParseStyle, "ParseStyle" },
+ { Event::ParseTile, "ParseTile" },
+ { Event::Render, "Render" },
+ { Event::Style, "Style" },
+ { Event::Database, "Database" },
+ { Event::HttpRequest, "HttpRequest" },
+ { Event::Sprite, "Sprite" },
+ { Event::Image, "Image" },
+ { Event::OpenGL, "OpenGL" },
+ { Event::JNI, "JNI" },
+ { Event::Android, "Android" },
+ { Event::Crash, "Crash" },
+ { Event::Glyph, "Glyph" },
+ { Event(-1), "Unknown" },
+});
+
+} // namespace mbgl
diff --git a/src/mbgl/platform/log.cpp b/src/mbgl/platform/log.cpp
index 2118511592..b140485dd6 100644
--- a/src/mbgl/platform/log.cpp
+++ b/src/mbgl/platform/log.cpp
@@ -1,4 +1,6 @@
#include <mbgl/platform/log.hpp>
+#include <mbgl/util/enum.hpp>
+#include <mbgl/util/thread.hpp>
#include <cstdio>
#include <cstdarg>
@@ -48,13 +50,8 @@ void Log::record(EventSeverity severity, Event event, int64_t code, const std::s
std::stringstream logStream;
- #if !defined(__ANDROID__) && (defined( __APPLE__) || defined(__linux__))
- char name[32];
- pthread_getname_np(pthread_self(), name, sizeof(name));
- logStream << "{" << name << "}";
- #endif
-
- logStream << "[" << event << "]";
+ logStream << "{" << platform::getCurrentThreadName() << "}";
+ logStream << "[" << Enum<Event>::toString(event) << "]";
if (code >= 0) {
logStream << "(" << code << ")";
diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp
index f12ed1fb96..cf461e4389 100644
--- a/src/mbgl/renderer/bucket.hpp
+++ b/src/mbgl/renderer/bucket.hpp
@@ -2,9 +2,9 @@
#include <mbgl/gl/gl.hpp>
#include <mbgl/renderer/render_pass.hpp>
-#include <mbgl/util/atomic.hpp>
#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/mat4.hpp>
+
+#include <atomic>
#define BUFFER_OFFSET_0 ((GLbyte*)nullptr)
#define BUFFER_OFFSET(i) ((BUFFER_OFFSET_0) + (i))
@@ -12,28 +12,30 @@
namespace mbgl {
class Painter;
-class UnwrappedTileID;
+class PaintParameters;
class CollisionTile;
+class RenderTile;
namespace gl {
class ObjectStore;
-}
+class Config;
+} // namespace gl
namespace style {
class Layer;
-}
+} // namespace style
class Bucket : private util::noncopyable {
public:
- Bucket() : uploaded(false) {}
+ Bucket() = default;
// As long as this bucket has a Prepare render pass, this function is getting called. Typically,
// this only happens once when the bucket is being rendered for the first time.
- virtual void upload(gl::ObjectStore&) = 0;
+ virtual void upload(gl::ObjectStore&, gl::Config&) = 0;
// Every time this bucket is getting rendered, this function is called. This happens either
// once or twice (for Opaque and Transparent render passes).
- virtual void render(Painter&, const style::Layer&, const UnwrappedTileID&, const mat4&) = 0;
+ virtual void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) = 0;
virtual ~Bucket() = default;
@@ -41,7 +43,7 @@ public:
virtual bool needsClipping() const = 0;
- inline bool needsUpload() const {
+ bool needsUpload() const {
return !uploaded;
}
@@ -49,8 +51,7 @@ public:
virtual void swapRenderData() {}
protected:
- util::Atomic<bool> uploaded;
-
+ std::atomic<bool> uploaded { false };
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/circle_bucket.cpp b/src/mbgl/renderer/circle_bucket.cpp
index 4ae63fed46..0b5c45ccc2 100644
--- a/src/mbgl/renderer/circle_bucket.cpp
+++ b/src/mbgl/renderer/circle_bucket.cpp
@@ -16,17 +16,17 @@ CircleBucket::~CircleBucket() {
// Do not remove. header file only contains forward definitions to unique pointers.
}
-void CircleBucket::upload(gl::ObjectStore& store) {
+void CircleBucket::upload(gl::ObjectStore& store, gl::Config&) {
vertexBuffer_.upload(store);
elementsBuffer_.upload(store);
uploaded = true;
}
void CircleBucket::render(Painter& painter,
+ PaintParameters& parameters,
const Layer& layer,
- const UnwrappedTileID& tileID,
- const mat4& matrix) {
- painter.renderCircle(*this, *layer.as<CircleLayer>(), tileID, matrix);
+ const RenderTile& tile) {
+ painter.renderCircle(parameters, *this, *layer.as<CircleLayer>(), tile);
}
bool CircleBucket::hasData() const {
@@ -100,4 +100,4 @@ void CircleBucket::drawCircles(CircleShader& shader, gl::ObjectStore& store) {
}
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/circle_bucket.hpp b/src/mbgl/renderer/circle_bucket.hpp
index fa34aa088a..617a9e5b24 100644
--- a/src/mbgl/renderer/circle_bucket.hpp
+++ b/src/mbgl/renderer/circle_bucket.hpp
@@ -2,7 +2,7 @@
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/map/mode.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
#include <mbgl/geometry/circle_buffer.hpp>
@@ -18,8 +18,8 @@ public:
CircleBucket(const MapMode);
~CircleBucket() override;
- void upload(gl::ObjectStore&) override;
- void render(Painter&, const style::Layer&, const UnwrappedTileID&, const mat4&) override;
+ void upload(gl::ObjectStore&, gl::Config&) override;
+ void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
bool hasData() const override;
bool needsClipping() const override;
diff --git a/src/mbgl/renderer/debug_bucket.cpp b/src/mbgl/renderer/debug_bucket.cpp
index 8c7a25c675..b4218485b2 100644
--- a/src/mbgl/renderer/debug_bucket.cpp
+++ b/src/mbgl/renderer/debug_bucket.cpp
@@ -8,7 +8,7 @@
#include <cassert>
#include <string>
-using namespace mbgl;
+namespace mbgl {
DebugBucket::DebugBucket(const OverscaledTileID& id,
const bool renderable_,
@@ -51,3 +51,5 @@ void DebugBucket::drawPoints(PlainShader& shader, gl::ObjectStore& store) {
MBGL_CHECK_ERROR(glDrawArrays(GL_POINTS, 0, (GLsizei)(fontBuffer.index())));
}
}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/debug_bucket.hpp b/src/mbgl/renderer/debug_bucket.hpp
index d69014bb8b..7097ae0735 100644
--- a/src/mbgl/renderer/debug_bucket.hpp
+++ b/src/mbgl/renderer/debug_bucket.hpp
@@ -1,6 +1,5 @@
#pragma once
-#include <mbgl/tile/tile_data.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/geometry/debug_font_buffer.hpp>
#include <mbgl/geometry/vao.hpp>
@@ -8,11 +7,12 @@
namespace mbgl {
+class OverscaledTileID;
class PlainShader;
namespace gl {
class ObjectStore;
-}
+} // namespace gl
class DebugBucket : private util::noncopyable {
public:
diff --git a/src/mbgl/renderer/fill_bucket.cpp b/src/mbgl/renderer/fill_bucket.cpp
index 02f346decb..4622c2097e 100644
--- a/src/mbgl/renderer/fill_bucket.cpp
+++ b/src/mbgl/renderer/fill_bucket.cpp
@@ -15,14 +15,14 @@
namespace mapbox {
namespace util {
template <> struct nth<0, mbgl::GeometryCoordinate> {
- inline static int64_t get(const mbgl::GeometryCoordinate& t) { return t.x; };
+ static int64_t get(const mbgl::GeometryCoordinate& t) { return t.x; };
};
template <> struct nth<1, mbgl::GeometryCoordinate> {
- inline static int64_t get(const mbgl::GeometryCoordinate& t) { return t.y; };
+ static int64_t get(const mbgl::GeometryCoordinate& t) { return t.y; };
};
-}
-}
+} // namespace util
+} // namespace mapbox
namespace mbgl {
@@ -33,8 +33,7 @@ struct GeometryTooLongException : std::exception {};
FillBucket::FillBucket() {
}
-FillBucket::~FillBucket() {
-}
+FillBucket::~FillBucket() = default;
void FillBucket::addGeometry(const GeometryCollection& geometry) {
for (auto& polygon : classifyRings(geometry)) {
@@ -96,7 +95,7 @@ void FillBucket::addGeometry(const GeometryCollection& geometry) {
}
}
-void FillBucket::upload(gl::ObjectStore& store) {
+void FillBucket::upload(gl::ObjectStore& store, gl::Config&) {
vertexBuffer.upload(store);
triangleElementsBuffer.upload(store);
lineElementsBuffer.upload(store);
@@ -106,10 +105,10 @@ void FillBucket::upload(gl::ObjectStore& store) {
}
void FillBucket::render(Painter& painter,
+ PaintParameters& parameters,
const Layer& layer,
- const UnwrappedTileID& tileID,
- const mat4& matrix) {
- painter.renderFill(*this, *layer.as<FillLayer>(), tileID, matrix);
+ const RenderTile& tile) {
+ painter.renderFill(parameters, *this, *layer.as<FillLayer>(), tile);
}
bool FillBucket::hasData() const {
@@ -120,52 +119,52 @@ bool FillBucket::needsClipping() const {
return true;
}
-void FillBucket::drawElements(PlainShader& shader, gl::ObjectStore& store) {
+void FillBucket::drawElements(PlainShader& shader, gl::ObjectStore& store, bool overdraw) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : triangleGroups) {
assert(group);
- group->array[0].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, store);
+ group->array[overdraw ? 1 : 0].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, store);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
elements_index += group->elements_length * triangleElementsBuffer.itemSize;
}
}
-void FillBucket::drawElements(PatternShader& shader, gl::ObjectStore& store) {
+void FillBucket::drawElements(PatternShader& shader, gl::ObjectStore& store, bool overdraw) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : triangleGroups) {
assert(group);
- group->array[1].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, store);
+ group->array[overdraw ? 3 : 2].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, store);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
elements_index += group->elements_length * triangleElementsBuffer.itemSize;
}
}
-void FillBucket::drawVertices(OutlineShader& shader, gl::ObjectStore& store) {
+void FillBucket::drawVertices(OutlineShader& shader, gl::ObjectStore& store, bool overdraw) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : lineGroups) {
assert(group);
- group->array[0].bind(shader, vertexBuffer, lineElementsBuffer, vertex_index, store);
+ group->array[overdraw ? 1 : 0].bind(shader, vertexBuffer, lineElementsBuffer, vertex_index, store);
MBGL_CHECK_ERROR(glDrawElements(GL_LINES, group->elements_length * 2, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
elements_index += group->elements_length * lineElementsBuffer.itemSize;
}
}
-void FillBucket::drawVertices(OutlinePatternShader& shader, gl::ObjectStore& store) {
+void FillBucket::drawVertices(OutlinePatternShader& shader, gl::ObjectStore& store, bool overdraw) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : lineGroups) {
assert(group);
- group->array[1].bind(shader, vertexBuffer, lineElementsBuffer, vertex_index, store);
+ group->array[overdraw? 3 : 2].bind(shader, vertexBuffer, lineElementsBuffer, vertex_index, store);
MBGL_CHECK_ERROR(glDrawElements(GL_LINES, group->elements_length * 2, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
elements_index += group->elements_length * lineElementsBuffer.itemSize;
}
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/fill_bucket.hpp b/src/mbgl/renderer/fill_bucket.hpp
index 35d70d169c..cacda975f0 100644
--- a/src/mbgl/renderer/fill_bucket.hpp
+++ b/src/mbgl/renderer/fill_bucket.hpp
@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
#include <mbgl/geometry/fill_buffer.hpp>
@@ -20,25 +20,25 @@ public:
FillBucket();
~FillBucket() override;
- void upload(gl::ObjectStore&) override;
- void render(Painter&, const style::Layer&, const UnwrappedTileID&, const mat4&) override;
+ void upload(gl::ObjectStore&, gl::Config&) override;
+ void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
bool hasData() const override;
bool needsClipping() const override;
void addGeometry(const GeometryCollection&);
- void drawElements(PlainShader&, gl::ObjectStore&);
- void drawElements(PatternShader&, gl::ObjectStore&);
- void drawVertices(OutlineShader&, gl::ObjectStore&);
- void drawVertices(OutlinePatternShader&, gl::ObjectStore&);
+ void drawElements(PlainShader&, gl::ObjectStore&, bool overdraw);
+ void drawElements(PatternShader&, gl::ObjectStore&, bool overdraw);
+ void drawVertices(OutlineShader&, gl::ObjectStore&, bool overdraw);
+ void drawVertices(OutlinePatternShader&, gl::ObjectStore&, bool overdraw);
private:
FillVertexBuffer vertexBuffer;
TriangleElementsBuffer triangleElementsBuffer;
LineElementsBuffer lineElementsBuffer;
- typedef ElementGroup<2> TriangleGroup;
- typedef ElementGroup<2> LineGroup;
+ typedef ElementGroup<4> TriangleGroup;
+ typedef ElementGroup<4> LineGroup;
std::vector<std::unique_ptr<TriangleGroup>> triangleGroups;
std::vector<std::unique_ptr<LineGroup>> lineGroups;
diff --git a/src/mbgl/renderer/frame_history.cpp b/src/mbgl/renderer/frame_history.cpp
index dbaf8fbf7a..fc9d9b6616 100644
--- a/src/mbgl/renderer/frame_history.cpp
+++ b/src/mbgl/renderer/frame_history.cpp
@@ -1,12 +1,13 @@
#include <mbgl/renderer/frame_history.hpp>
#include <mbgl/math/minmax.hpp>
+#include <mbgl/gl/gl_config.hpp>
-using namespace mbgl;
+namespace mbgl {
FrameHistory::FrameHistory() {
changeOpacities.fill(0);
opacities.fill(0);
-};
+}
void FrameHistory::record(const TimePoint& now, float zoom, const Duration& duration) {
@@ -57,11 +58,11 @@ bool FrameHistory::needsAnimation(const Duration& duration) const {
return (time - previousTime) < duration;
}
-void FrameHistory::upload(gl::ObjectStore& store) {
+void FrameHistory::upload(gl::ObjectStore& store, gl::Config& config, uint32_t unit) {
if (changed) {
const bool first = !texture;
- bind(store);
+ bind(store, config, unit);
if (first) {
MBGL_CHECK_ERROR(glTexImage2D(
@@ -94,10 +95,11 @@ void FrameHistory::upload(gl::ObjectStore& store) {
}
}
-void FrameHistory::bind(gl::ObjectStore& store) {
+void FrameHistory::bind(gl::ObjectStore& store, gl::Config& config, uint32_t unit) {
if (!texture) {
texture = store.createTexture();
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
+ config.activeTexture = unit;
+ config.texture[unit] = *texture;
#ifndef GL_ES_VERSION_2_0
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
#endif
@@ -105,8 +107,10 @@ void FrameHistory::bind(gl::ObjectStore& store) {
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
- } else {
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
+ } else if (config.texture[unit] != *texture) {
+ config.activeTexture = unit;
+ config.texture[unit] = *texture;
}
-
}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/frame_history.hpp b/src/mbgl/renderer/frame_history.hpp
index 04ebe23276..ec43e2beb5 100644
--- a/src/mbgl/renderer/frame_history.hpp
+++ b/src/mbgl/renderer/frame_history.hpp
@@ -9,14 +9,18 @@
namespace mbgl {
+namespace gl {
+class Config;
+} // namespace gl
+
class FrameHistory {
public:
FrameHistory();
void record(const TimePoint&, float zoom, const Duration&);
bool needsAnimation(const Duration&) const;
- void bind(gl::ObjectStore&);
- void upload(gl::ObjectStore&);
+ void bind(gl::ObjectStore&, gl::Config&, uint32_t);
+ void upload(gl::ObjectStore&, gl::Config&, uint32_t);
private:
const int width = 256;
diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp
index d207cdb8c5..e9f920efa6 100644
--- a/src/mbgl/renderer/line_bucket.cpp
+++ b/src/mbgl/renderer/line_bucket.cpp
@@ -437,7 +437,7 @@ void LineBucket::addPieSliceVertex(const GeometryCoordinate& currentVertex,
}
}
-void LineBucket::upload(gl::ObjectStore& store) {
+void LineBucket::upload(gl::ObjectStore& store, gl::Config&) {
vertexBuffer.upload(store);
triangleElementsBuffer.upload(store);
@@ -446,10 +446,10 @@ void LineBucket::upload(gl::ObjectStore& store) {
}
void LineBucket::render(Painter& painter,
+ PaintParameters& parameters,
const Layer& layer,
- const UnwrappedTileID& tileID,
- const mat4& matrix) {
- painter.renderLine(*this, *layer.as<LineLayer>(), tileID, matrix);
+ const RenderTile& tile) {
+ painter.renderLine(parameters, *this, *layer.as<LineLayer>(), tile);
}
bool LineBucket::hasData() const {
@@ -460,7 +460,7 @@ bool LineBucket::needsClipping() const {
return true;
}
-void LineBucket::drawLines(LineShader& shader, gl::ObjectStore& store) {
+void LineBucket::drawLines(LineShader& shader, gl::ObjectStore& store, bool overdraw) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : triangleGroups) {
@@ -468,7 +468,7 @@ void LineBucket::drawLines(LineShader& shader, gl::ObjectStore& store) {
if (!group->elements_length) {
continue;
}
- group->array[0].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, store);
+ group->array[overdraw ? 1 : 0].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, store);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT,
elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
@@ -476,7 +476,7 @@ void LineBucket::drawLines(LineShader& shader, gl::ObjectStore& store) {
}
}
-void LineBucket::drawLineSDF(LineSDFShader& shader, gl::ObjectStore& store) {
+void LineBucket::drawLineSDF(LineSDFShader& shader, gl::ObjectStore& store, bool overdraw) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : triangleGroups) {
@@ -484,7 +484,7 @@ void LineBucket::drawLineSDF(LineSDFShader& shader, gl::ObjectStore& store) {
if (!group->elements_length) {
continue;
}
- group->array[2].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, store);
+ group->array[overdraw ? 3 : 2].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, store);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT,
elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
@@ -492,7 +492,7 @@ void LineBucket::drawLineSDF(LineSDFShader& shader, gl::ObjectStore& store) {
}
}
-void LineBucket::drawLinePatterns(LinepatternShader& shader, gl::ObjectStore& store) {
+void LineBucket::drawLinePatterns(LinepatternShader& shader, gl::ObjectStore& store, bool overdraw) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : triangleGroups) {
@@ -500,7 +500,7 @@ void LineBucket::drawLinePatterns(LinepatternShader& shader, gl::ObjectStore& st
if (!group->elements_length) {
continue;
}
- group->array[1].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, store);
+ group->array[overdraw ? 5 : 4].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, store);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT,
elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
@@ -508,4 +508,4 @@ void LineBucket::drawLinePatterns(LinepatternShader& shader, gl::ObjectStore& st
}
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/line_bucket.hpp
index d746f29c7e..6687faab4c 100644
--- a/src/mbgl/renderer/line_bucket.hpp
+++ b/src/mbgl/renderer/line_bucket.hpp
@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/geometry/vao.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
#include <mbgl/geometry/line_buffer.hpp>
@@ -18,23 +18,23 @@ class LineSDFShader;
class LinepatternShader;
class LineBucket : public Bucket {
- using TriangleGroup = ElementGroup<3>;
+ using TriangleGroup = ElementGroup<6>;
public:
LineBucket(uint32_t overscaling);
~LineBucket() override;
- void upload(gl::ObjectStore&) override;
- void render(Painter&, const style::Layer&, const UnwrappedTileID&, const mat4&) override;
+ void upload(gl::ObjectStore&, gl::Config&) override;
+ void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
bool hasData() const override;
bool needsClipping() const override;
void addGeometry(const GeometryCollection&);
void addGeometry(const GeometryCoordinates& line);
- void drawLines(LineShader&, gl::ObjectStore&);
- void drawLineSDF(LineSDFShader&, gl::ObjectStore&);
- void drawLinePatterns(LinepatternShader&, gl::ObjectStore&);
+ void drawLines(LineShader&, gl::ObjectStore&, bool overdraw);
+ void drawLineSDF(LineSDFShader&, gl::ObjectStore&, bool overdraw);
+ void drawLinePatterns(LinepatternShader&, gl::ObjectStore&, bool overdraw);
private:
struct TriangleElement {
diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp
new file mode 100644
index 0000000000..13bf21080d
--- /dev/null
+++ b/src/mbgl/renderer/paint_parameters.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+namespace mbgl {
+
+class Shaders;
+
+class PaintParameters {
+public:
+ Shaders& shaders;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp
index 1864bf7ef1..b196c71b96 100644
--- a/src/mbgl/renderer/painter.cpp
+++ b/src/mbgl/renderer/painter.cpp
@@ -1,7 +1,9 @@
#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/style/source.hpp>
-#include <mbgl/tile/tile.hpp>
+#include <mbgl/style/source_impl.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/gl/debugging.hpp>
@@ -17,18 +19,7 @@
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/geometry/glyph_atlas.hpp>
-#include <mbgl/shader/pattern_shader.hpp>
-#include <mbgl/shader/plain_shader.hpp>
-#include <mbgl/shader/outline_shader.hpp>
-#include <mbgl/shader/outlinepattern_shader.hpp>
-#include <mbgl/shader/line_shader.hpp>
-#include <mbgl/shader/linesdf_shader.hpp>
-#include <mbgl/shader/linepattern_shader.hpp>
-#include <mbgl/shader/icon_shader.hpp>
-#include <mbgl/shader/raster_shader.hpp>
-#include <mbgl/shader/sdf_shader.hpp>
-#include <mbgl/shader/collision_box_shader.hpp>
-#include <mbgl/shader/circle_shader.hpp>
+#include <mbgl/shader/shaders.hpp>
#include <mbgl/algorithm/generate_clip_ids.hpp>
#include <mbgl/algorithm/generate_clip_ids_impl.hpp>
@@ -49,26 +40,18 @@ namespace mbgl {
using namespace style;
-Painter::Painter(const TransformState& state_, gl::ObjectStore& store_)
- : state(state_),
- store(store_) {
+Painter::Painter(const TransformState& state_,
+ gl::ObjectStore& store_)
+ : state(state_), store(store_) {
gl::debugging::enable();
- plainShader = std::make_unique<PlainShader>(store);
- outlineShader = std::make_unique<OutlineShader>(store);
- outlinePatternShader = std::make_unique<OutlinePatternShader>(store);
- lineShader = std::make_unique<LineShader>(store);
- linesdfShader = std::make_unique<LineSDFShader>(store);
- linepatternShader = std::make_unique<LinepatternShader>(store);
- patternShader = std::make_unique<PatternShader>(store);
- iconShader = std::make_unique<IconShader>(store);
- rasterShader = std::make_unique<RasterShader>(store);
- sdfGlyphShader = std::make_unique<SDFGlyphShader>(store);
- sdfIconShader = std::make_unique<SDFIconShader>(store);
- collisionBoxShader = std::make_unique<CollisionBoxShader>(store);
- circleShader = std::make_unique<CircleShader>(store);
+ shaders = std::make_unique<Shaders>(store);
+#if defined(DEBUG)
+ overdrawShaders = std::make_unique<Shaders>(store, Shader::Overdraw);
+#endif
// Reset GL values
+ config.setDirty();
config.reset();
}
@@ -87,11 +70,19 @@ void Painter::setClipping(const ClipID& clip) {
void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& annotationSpriteAtlas) {
frame = frame_;
+ PaintParameters parameters {
+#if defined(DEBUG)
+ isOverdraw() ? *overdrawShaders : *shaders
+#else
+ *shaders
+#endif
+ };
+
glyphAtlas = style.glyphAtlas.get();
spriteAtlas = style.spriteAtlas.get();
lineAtlas = style.lineAtlas.get();
- RenderData renderData = style.getRenderData();
+ RenderData renderData = style.getRenderData(frame.debugOptions);
const std::vector<RenderItem>& order = renderData.order;
const std::set<Source*>& sources = renderData.sources;
const Color& background = renderData.backgroundColor;
@@ -99,15 +90,10 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
// Update the default matrices to the current viewport dimensions.
state.getProjMatrix(projMatrix);
- // The extrusion scale.
- const float flippedY = state.getViewportMode() == ViewportMode::FlippedY;
- extrudeScale = {{ 2.0f / state.getWidth() * state.getAltitude(),
- (flippedY ? 2.0f : -2.0f) / state.getHeight() * state.getAltitude() }};
-
- // The native matrix is a 1:1 matrix that paints the coordinates at the
- // same screen position as the vertex specifies.
- matrix::identity(nativeMatrix);
- matrix::multiply(nativeMatrix, projMatrix, nativeMatrix);
+ pixelsToGLUnits = {{ 2.0f / state.getWidth(), -2.0f / state.getHeight() }};
+ if (state.getViewportMode() == ViewportMode::FlippedY) {
+ pixelsToGLUnits[1] *= -1;
+ }
frameHistory.record(frame.timePoint, state.getZoom(),
frame.mapMode == MapMode::Continuous ? util::DEFAULT_FADE_DURATION : Milliseconds(0));
@@ -118,16 +104,17 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
MBGL_DEBUG_GROUP("upload");
tileStencilBuffer.upload(store);
+ rasterBoundsBuffer.upload(store);
tileBorderBuffer.upload(store);
- spriteAtlas->upload(store);
- lineAtlas->upload(store);
- glyphAtlas->upload(store);
- frameHistory.upload(store);
- annotationSpriteAtlas.upload(store);
+ spriteAtlas->upload(store, config, 0);
+ lineAtlas->upload(store, config, 0);
+ glyphAtlas->upload(store, config, 0);
+ frameHistory.upload(store, config, 0);
+ annotationSpriteAtlas.upload(store, config, 0);
for (const auto& item : order) {
if (item.bucket && item.bucket->needsUpload()) {
- item.bucket->upload(store);
+ item.bucket->upload(store, config);
}
}
}
@@ -143,10 +130,15 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
config.depthTest = GL_FALSE;
config.depthMask = GL_TRUE;
config.colorMask = { GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE };
- if (frame.debugOptions & MapDebugOptions::Wireframe) {
- config.clearColor = { 0.0f, 0.0f, 0.0f, 1.0f };
+
+ if (isOverdraw()) {
+ config.blend = GL_TRUE;
+ config.blendFunc = { GL_CONSTANT_COLOR, GL_ONE };
+ const float overdraw = 1.0f / 8.0f;
+ config.blendColor = { overdraw, overdraw, overdraw, 0.0f };
+ config.clearColor = Color::black();
} else {
- config.clearColor = { background[0], background[1], background[2], background[3] };
+ config.clearColor = background;
}
config.clearStencil = 0;
config.clearDepth = 1;
@@ -161,20 +153,18 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
// Update all clipping IDs.
algorithm::ClipIDGenerator generator;
for (const auto& source : sources) {
- if (source->type == SourceType::Vector || source->type == SourceType::GeoJSON ||
- source->type == SourceType::Annotations) {
- source->updateClipIDs(generator);
- }
- source->updateMatrices(projMatrix, state);
+ source->baseImpl->startRender(generator, projMatrix, state);
}
- drawClippingMasks(generator.getStencils());
+ drawClippingMasks(parameters, generator.getStencils());
}
+#if defined(DEBUG)
if (frame.debugOptions & MapDebugOptions::StencilClip) {
renderClipMasks();
return;
}
+#endif
// Actually render the layers
if (debug::renderTree) { Log::Info(Event::Render, "{"); indent++; }
@@ -184,13 +174,15 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
// - OPAQUE PASS -------------------------------------------------------------------------------
// Render everything top-to-bottom by using reverse iterators. Render opaque objects first.
- renderPass(RenderPass::Opaque,
+ renderPass(parameters,
+ RenderPass::Opaque,
order.rbegin(), order.rend(),
0, 1);
// - TRANSLUCENT PASS --------------------------------------------------------------------------
// Make a second pass, rendering translucent objects. This time, we render bottom-to-top.
- renderPass(RenderPass::Translucent,
+ renderPass(parameters,
+ RenderPass::Translucent,
order.begin(), order.end(),
static_cast<GLsizei>(order.size()) - 1, -1);
@@ -206,7 +198,7 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
// When only rendering layers via the stylesheet, it's possible that we don't
// ever visit a tile during rendering.
for (const auto& source : sources) {
- source->finishRender(*this);
+ source->baseImpl->finishRender(*this);
}
}
@@ -215,7 +207,11 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
{
MBGL_DEBUG_GROUP("cleanup");
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, 0));
+ config.activeTexture = 1;
+ config.texture[1] = 0;
+ config.activeTexture = 0;
+ config.texture[0] = 0;
+
MBGL_CHECK_ERROR(VertexArrayObject::Unbind());
}
@@ -225,7 +221,8 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
}
template <class Iterator>
-void Painter::renderPass(RenderPass pass_,
+void Painter::renderPass(PaintParameters& parameters,
+ RenderPass pass_,
Iterator it, Iterator end,
GLsizei i, int8_t increment) {
pass = pass_;
@@ -246,7 +243,9 @@ void Painter::renderPass(RenderPass pass_,
if (!layer.baseImpl->hasRenderPass(pass))
continue;
- if (pass == RenderPass::Translucent) {
+ if (isOverdraw()) {
+ config.blend = GL_TRUE;
+ } else if (pass == RenderPass::Translucent) {
config.blendFunc.reset();
config.blend = GL_TRUE;
} else {
@@ -258,7 +257,7 @@ void Painter::renderPass(RenderPass pass_,
if (layer.is<BackgroundLayer>()) {
MBGL_DEBUG_GROUP("background");
- renderBackground(*layer.as<BackgroundLayer>());
+ renderBackground(parameters, *layer.as<BackgroundLayer>());
} else if (layer.is<CustomLayer>()) {
MBGL_DEBUG_GROUP(layer.baseImpl->id + " - custom");
VertexArrayObject::Unbind();
@@ -269,7 +268,7 @@ void Painter::renderPass(RenderPass pass_,
if (item.bucket->needsClipping()) {
setClipping(item.tile->clip);
}
- item.bucket->render(*this, layer, item.tile->id, item.tile->matrix);
+ item.bucket->render(*this, parameters, layer, *item.tile);
}
}
@@ -278,36 +277,10 @@ void Painter::renderPass(RenderPass pass_,
}
}
-mat4 Painter::translatedMatrix(const mat4& matrix,
- const std::array<float, 2>& translation,
- const UnwrappedTileID& id,
- TranslateAnchorType anchor) {
- if (translation[0] == 0 && translation[1] == 0) {
- return matrix;
- } else {
- mat4 vtxMatrix;
- if (anchor == TranslateAnchorType::Viewport) {
- const double sin_a = std::sin(-state.getAngle());
- const double cos_a = std::cos(-state.getAngle());
- matrix::translate(vtxMatrix, matrix,
- id.pixelsToTileUnits(translation[0] * cos_a - translation[1] * sin_a, state.getZoom()),
- id.pixelsToTileUnits(translation[0] * sin_a + translation[1] * cos_a, state.getZoom()),
- 0);
- } else {
- matrix::translate(vtxMatrix, matrix,
- id.pixelsToTileUnits(translation[0], state.getZoom()),
- id.pixelsToTileUnits(translation[1], state.getZoom()),
- 0);
- }
-
- return vtxMatrix;
- }
-}
-
void Painter::setDepthSublayer(int n) {
float nearDepth = ((1 + currentLayer) * numSublayers + n) * depthEpsilon;
float farDepth = nearDepth + depthRangeSize;
config.depthRange = { nearDepth, farDepth };
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp
index 25627a8d7a..b291c14b14 100644
--- a/src/mbgl/renderer/painter.hpp
+++ b/src/mbgl/renderer/painter.hpp
@@ -27,12 +27,12 @@
namespace mbgl {
-class Tile;
+class RenderTile;
class SpriteAtlas;
class GlyphAtlas;
class LineAtlas;
struct FrameData;
-class TileData;
+class Tile;
class DebugBucket;
class FillBucket;
@@ -41,27 +41,15 @@ class CircleBucket;
class SymbolBucket;
class RasterBucket;
+class Shaders;
class SDFShader;
-class PlainShader;
-class OutlineShader;
-class OutlinePatternShader;
-class LineShader;
-class LinejoinShader;
-class LineSDFShader;
-class LinepatternShader;
-class CircleShader;
-class PatternShader;
-class IconShader;
-class RasterShader;
-class SDFGlyphShader;
-class SDFIconShader;
-class CollisionBoxShader;
+class PaintParameters;
struct ClipID;
namespace util {
class ObjectStore;
-}
+} // namespace util
namespace style {
class Style;
@@ -72,7 +60,7 @@ class CircleLayer;
class SymbolLayer;
class RasterLayer;
class BackgroundLayer;
-}
+} // namespace style
struct FrameData {
std::array<uint16_t, 2> framebufferSize;
@@ -93,54 +81,53 @@ public:
SpriteAtlas& annotationSpriteAtlas);
// Renders debug information for a tile.
- void renderTileDebug(const Tile& tile);
+ void renderTileDebug(const RenderTile&);
// Renders the red debug frame around a tile, visualizing its perimeter.
void renderDebugFrame(const mat4 &matrix);
+#if defined(DEBUG)
+ // Renders tile clip boundaries, using stencil buffer to calculate fill color.
void renderClipMasks();
+#endif
- void renderDebugText(TileData&, const mat4&);
- void renderFill(FillBucket&, const style::FillLayer&, const UnwrappedTileID&, const mat4&);
- void renderLine(LineBucket&, const style::LineLayer&, const UnwrappedTileID&, const mat4&);
- void renderCircle(CircleBucket&, const style::CircleLayer&, const UnwrappedTileID&, const mat4&);
- void renderSymbol(SymbolBucket&, const style::SymbolLayer&, const UnwrappedTileID&, const mat4&);
- void renderRaster(RasterBucket&, const style::RasterLayer&, const UnwrappedTileID&, const mat4&);
- void renderBackground(const style::BackgroundLayer&);
+ void renderDebugText(Tile&, const mat4&);
+ void renderFill(PaintParameters&, FillBucket&, const style::FillLayer&, const RenderTile&);
+ void renderLine(PaintParameters&, LineBucket&, const style::LineLayer&, const RenderTile&);
+ void renderCircle(PaintParameters&, CircleBucket&, const style::CircleLayer&, const RenderTile&);
+ void renderSymbol(PaintParameters&, SymbolBucket&, const style::SymbolLayer&, const RenderTile&);
+ void renderRaster(PaintParameters&, RasterBucket&, const style::RasterLayer&, const RenderTile&);
+ void renderBackground(PaintParameters&, const style::BackgroundLayer&);
float saturationFactor(float saturation);
float contrastFactor(float contrast);
std::array<float, 3> spinWeights(float spin_value);
- void drawClippingMasks(const std::map<UnwrappedTileID, ClipID>&);
+ void drawClippingMasks(PaintParameters&, const std::map<UnwrappedTileID, ClipID>&);
bool needsAnimation() const;
private:
- mat4 translatedMatrix(const mat4& matrix,
- const std::array<float, 2>& translation,
- const UnwrappedTileID& id,
- style::TranslateAnchorType anchor);
-
std::vector<RenderItem> determineRenderOrder(const style::Style&);
template <class Iterator>
- void renderPass(RenderPass,
+ void renderPass(PaintParameters&,
+ RenderPass,
Iterator it, Iterator end,
GLsizei i, int8_t increment);
void setClipping(const ClipID&);
- void renderSDF(SymbolBucket &bucket,
- const UnwrappedTileID &tileID,
- const mat4 &matrixSymbol,
+ void renderSDF(SymbolBucket&,
+ const RenderTile&,
float scaleDivisor,
std::array<float, 2> texsize,
SDFShader& sdfShader,
- void (SymbolBucket::*drawSDF)(SDFShader&, gl::ObjectStore&),
+ void (SymbolBucket::*drawSDF)(SDFShader&, gl::ObjectStore&, bool),
// Layout
- style::RotationAlignmentType rotationAlignment,
+ style::AlignmentType rotationAlignment,
+ style::AlignmentType pitchAlignment,
float layoutSize,
// Paint
@@ -155,18 +142,15 @@ private:
void setDepthSublayer(int n);
- mat4 projMatrix;
- mat4 nativeMatrix;
+#if defined(DEBUG)
+ bool isOverdraw() const { return frame.debugOptions & MapDebugOptions::Overdraw; }
+#else
+ bool isOverdraw() const { return false; }
+#endif
- std::array<float, 2> extrudeScale;
+ mat4 projMatrix;
- // used to composite images and flips the geometry upside down
- const mat4 flipMatrix = []{
- mat4 flip;
- matrix::ortho(flip, 0, util::EXTENT, -util::EXTENT, 0, 0, 1);
- matrix::translate(flip, flip, 0, -util::EXTENT, 0);
- return flip;
- }();
+ std::array<float, 2> pixelsToGLUnits;
const mat4 identityMatrix = []{
mat4 identity;
@@ -196,45 +180,38 @@ private:
FrameHistory frameHistory;
- std::unique_ptr<PlainShader> plainShader;
- std::unique_ptr<OutlineShader> outlineShader;
- std::unique_ptr<OutlinePatternShader> outlinePatternShader;
- std::unique_ptr<LineShader> lineShader;
- std::unique_ptr<LineSDFShader> linesdfShader;
- std::unique_ptr<LinepatternShader> linepatternShader;
- std::unique_ptr<PatternShader> patternShader;
- std::unique_ptr<IconShader> iconShader;
- std::unique_ptr<RasterShader> rasterShader;
- std::unique_ptr<SDFGlyphShader> sdfGlyphShader;
- std::unique_ptr<SDFIconShader> sdfIconShader;
- std::unique_ptr<CollisionBoxShader> collisionBoxShader;
- std::unique_ptr<CircleShader> circleShader;
+ std::unique_ptr<Shaders> shaders;
+#if defined(DEBUG)
+ std::unique_ptr<Shaders> overdrawShaders;
+#endif
// Set up the stencil quad we're using to generate the stencil mask.
- StaticVertexBuffer tileStencilBuffer = {
+ StaticVertexBuffer tileStencilBuffer {
// top left triangle
- { 0, 0 },
- { util::EXTENT, 0 },
- { 0, util::EXTENT },
+ {{ 0, 0 }},
+ {{ util::EXTENT, 0 }},
+ {{ 0, util::EXTENT }},
// bottom right triangle
- { util::EXTENT, 0 },
- { 0, util::EXTENT },
- { util::EXTENT, util::EXTENT },
+ {{ util::EXTENT, 0 }},
+ {{ 0, util::EXTENT }},
+ {{ util::EXTENT, util::EXTENT }},
};
- VertexArrayObject coveringPlainArray;
- VertexArrayObject coveringRasterArray;
- VertexArrayObject backgroundPatternArray;
- VertexArrayObject backgroundArray;
+ StaticRasterVertexBuffer rasterBoundsBuffer {
+ {{ 0, 0, 0, 0 }},
+ {{ util::EXTENT, 0, 32767, 0 }},
+ {{ 0, util::EXTENT, 0, 32767 }},
+ {{ util::EXTENT, util::EXTENT, 32767, 32767 }},
+ };
// Set up the tile boundary lines we're using to draw the tile outlines.
- StaticVertexBuffer tileBorderBuffer = {
- { 0, 0 },
- { util::EXTENT, 0 },
- { util::EXTENT, util::EXTENT },
- { 0, util::EXTENT },
- { 0, 0 },
+ StaticVertexBuffer tileBorderBuffer {
+ {{ 0, 0 }},
+ {{ util::EXTENT, 0 }},
+ {{ util::EXTENT, util::EXTENT }},
+ {{ 0, util::EXTENT }},
+ {{ 0, 0 }},
};
VertexArrayObject tileBorderArray;
diff --git a/src/mbgl/renderer/painter_background.cpp b/src/mbgl/renderer/painter_background.cpp
index 07e5821ce8..51a892575b 100644
--- a/src/mbgl/renderer/painter_background.cpp
+++ b/src/mbgl/renderer/painter_background.cpp
@@ -1,9 +1,9 @@
#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/background_layer_impl.hpp>
-#include <mbgl/shader/pattern_shader.hpp>
-#include <mbgl/shader/plain_shader.hpp>
+#include <mbgl/shader/shaders.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/util/mat4.hpp>
#include <mbgl/util/tile_cover.hpp>
@@ -12,7 +12,7 @@ namespace mbgl {
using namespace style;
-void Painter::renderBackground(const BackgroundLayer& layer) {
+void Painter::renderBackground(PaintParameters& parameters, const BackgroundLayer& layer) {
// Note that for bottommost layers without a pattern, the background color is drawn with
// glClear rather than this method.
const BackgroundPaintProperties& properties = layer.impl->paint;
@@ -21,8 +21,10 @@ void Painter::renderBackground(const BackgroundLayer& layer) {
optional<SpriteAtlasPosition> imagePosA;
optional<SpriteAtlasPosition> imagePosB;
- bool wireframe = frame.debugOptions & MapDebugOptions::Wireframe;
- isPatterned &= !wireframe;
+ auto& patternShader = parameters.shaders.pattern;
+ auto& plainShader = parameters.shaders.plain;
+ auto& arrayBackgroundPattern = parameters.shaders.backgroundPatternArray;
+ auto& arrayBackground = parameters.shaders.backgroundArray;
if (isPatterned) {
imagePosA = spriteAtlas->getPosition(properties.backgroundPattern.value.from, true);
@@ -31,29 +33,24 @@ void Painter::renderBackground(const BackgroundLayer& layer) {
if (!imagePosA || !imagePosB)
return;
- config.program = patternShader->getID();
- patternShader->u_matrix = identityMatrix;
- patternShader->u_pattern_tl_a = (*imagePosA).tl;
- patternShader->u_pattern_br_a = (*imagePosA).br;
- patternShader->u_pattern_tl_b = (*imagePosB).tl;
- patternShader->u_pattern_br_b = (*imagePosB).br;
- patternShader->u_mix = properties.backgroundPattern.value.t;
- patternShader->u_opacity = properties.backgroundOpacity;
+ config.program = patternShader.getID();
+ patternShader.u_matrix = identityMatrix;
+ patternShader.u_pattern_tl_a = imagePosA->tl;
+ patternShader.u_pattern_br_a = imagePosA->br;
+ patternShader.u_pattern_tl_b = imagePosB->tl;
+ patternShader.u_pattern_br_b = imagePosB->br;
+ patternShader.u_mix = properties.backgroundPattern.value.t;
+ patternShader.u_opacity = properties.backgroundOpacity;
- spriteAtlas->bind(true, store);
- backgroundPatternArray.bind(*patternShader, tileStencilBuffer, BUFFER_OFFSET(0), store);
+ spriteAtlas->bind(true, store, config, 0);
+ arrayBackgroundPattern.bind(patternShader, tileStencilBuffer, BUFFER_OFFSET(0), store);
} else {
- if (wireframe) {
- plainShader->u_color = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
- plainShader->u_opacity = 1.0f;
- } else {
- plainShader->u_color = properties.backgroundColor;
- plainShader->u_opacity = properties.backgroundOpacity;
- }
+ config.program = plainShader.getID();
+ plainShader.u_color = properties.backgroundColor;
+ plainShader.u_opacity = properties.backgroundOpacity;
- config.program = plainShader->getID();
- backgroundArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0), store);
+ arrayBackground.bind(plainShader, tileStencilBuffer, BUFFER_OFFSET(0), store);
}
config.stencilTest = GL_FALSE;
@@ -62,52 +59,30 @@ void Painter::renderBackground(const BackgroundLayer& layer) {
config.depthMask = GL_FALSE;
setDepthSublayer(0);
- auto tileIDs = util::tileCover(state, state.getIntegerZoom());
-
- for (auto& id : tileIDs) {
- mat4 vtxMatrix;
- state.matrixFor(vtxMatrix, id);
- matrix::multiply(vtxMatrix, projMatrix, vtxMatrix);
+ for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) {
+ mat4 vertexMatrix;
+ state.matrixFor(vertexMatrix, tileID);
+ matrix::multiply(vertexMatrix, projMatrix, vertexMatrix);
if (isPatterned) {
- patternShader->u_matrix = vtxMatrix;
-
- std::array<int, 2> imageSizeScaledA = {{
- (int)((*imagePosA).size[0] * properties.backgroundPattern.value.fromScale),
- (int)((*imagePosA).size[1] * properties.backgroundPattern.value.fromScale)
- }};
- std::array<int, 2> imageSizeScaledB = {{
- (int)((*imagePosB).size[0] * properties.backgroundPattern.value.toScale),
- (int)((*imagePosB).size[1] * properties.backgroundPattern.value.toScale)
- }};
-
- patternShader->u_patternscale_a = {{
- 1.0f / id.pixelsToTileUnits(imageSizeScaledA[0], state.getIntegerZoom()),
- 1.0f / id.pixelsToTileUnits(imageSizeScaledA[1], state.getIntegerZoom())
- }};
- patternShader->u_patternscale_b = {{
- 1.0f / id.pixelsToTileUnits(imageSizeScaledB[0], state.getIntegerZoom()),
- 1.0f / id.pixelsToTileUnits(imageSizeScaledB[1], state.getIntegerZoom())
- }};
-
- float offsetAx = (std::fmod(util::tileSize, imageSizeScaledA[0]) * id.canonical.x) /
- (float)imageSizeScaledA[0];
- float offsetAy = (std::fmod(util::tileSize, imageSizeScaledA[1]) * id.canonical.y) /
- (float)imageSizeScaledA[1];
-
- float offsetBx = (std::fmod(util::tileSize, imageSizeScaledB[0]) * id.canonical.x) /
- (float)imageSizeScaledB[0];
- float offsetBy = (std::fmod(util::tileSize, imageSizeScaledB[1]) * id.canonical.y) /
- (float)imageSizeScaledB[1];
-
- patternShader->u_offset_a = std::array<float, 2>{{offsetAx, offsetAy}};
- patternShader->u_offset_b = std::array<float, 2>{{offsetBx, offsetBy}};
+ patternShader.u_matrix = vertexMatrix;
+ patternShader.u_pattern_size_a = imagePosA->size;
+ patternShader.u_pattern_size_b = imagePosB->size;
+ patternShader.u_scale_a = properties.backgroundPattern.value.fromScale;
+ patternShader.u_scale_b = properties.backgroundPattern.value.toScale;
+ patternShader.u_tile_units_to_pixels = 1.0f / tileID.pixelsToTileUnits(1.0f, state.getIntegerZoom());
+
+ GLint tileSizeAtNearestZoom = util::tileSize * state.zoomScale(state.getIntegerZoom() - tileID.canonical.z);
+ GLint pixelX = tileSizeAtNearestZoom * (tileID.canonical.x + tileID.wrap * state.zoomScale(tileID.canonical.z));
+ GLint pixelY = tileSizeAtNearestZoom * tileID.canonical.y;
+ patternShader.u_pixel_coord_upper = {{ float(pixelX >> 16), float(pixelY >> 16) }};
+ patternShader.u_pixel_coord_lower = {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }};
} else {
- plainShader->u_matrix = vtxMatrix;
+ plainShader.u_matrix = vertexMatrix;
}
MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)tileStencilBuffer.index()));
}
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_circle.cpp b/src/mbgl/renderer/painter_circle.cpp
index 9f2cd17f7f..f91370ff22 100644
--- a/src/mbgl/renderer/painter_circle.cpp
+++ b/src/mbgl/renderer/painter_circle.cpp
@@ -1,19 +1,21 @@
#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/circle_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/circle_layer_impl.hpp>
-#include <mbgl/shader/circle_shader.hpp>
+#include <mbgl/shader/shaders.hpp>
namespace mbgl {
using namespace style;
-void Painter::renderCircle(CircleBucket& bucket,
+void Painter::renderCircle(PaintParameters& parameters,
+ CircleBucket& bucket,
const CircleLayer& layer,
- const UnwrappedTileID& tileID,
- const mat4& matrix) {
+ const RenderTile& tile) {
// Abort early.
if (pass == RenderPass::Opaque) return;
@@ -24,26 +26,32 @@ void Painter::renderCircle(CircleBucket& bucket,
setDepthSublayer(0);
const CirclePaintProperties& properties = layer.impl->paint;
- mat4 vtxMatrix = translatedMatrix(matrix, properties.circleTranslate, tileID,
- properties.circleTranslateAnchor);
-
- // Antialiasing factor: this is a minimum blur distance that serves as
- // a faux-antialiasing for the circle. since blur is a ratio of the circle's
- // size and the intent is to keep the blur at roughly 1px, the two
- // are inversely related.
- float antialiasing = 1 / frame.pixelRatio / properties.circleRadius;
-
- config.program = circleShader->getID();
-
- circleShader->u_matrix = vtxMatrix;
- circleShader->u_extrude_scale = extrudeScale;
- circleShader->u_devicepixelratio = frame.pixelRatio;
- circleShader->u_color = properties.circleColor;
- circleShader->u_radius = properties.circleRadius;
- circleShader->u_blur = std::max<float>(properties.circleBlur, antialiasing);
- circleShader->u_opacity = properties.circleOpacity;
-
- bucket.drawCircles(*circleShader, store);
+ auto& circleShader = parameters.shaders.circle;
+
+ config.program = circleShader.getID();
+
+ circleShader.u_matrix = tile.translatedMatrix(properties.circleTranslate,
+ properties.circleTranslateAnchor,
+ state);
+
+ if (properties.circlePitchScale == CirclePitchScaleType::Map) {
+ circleShader.u_extrude_scale = {{
+ pixelsToGLUnits[0] * state.getAltitude(),
+ pixelsToGLUnits[1] * state.getAltitude()
+ }};
+ circleShader.u_scale_with_map = true;
+ } else {
+ circleShader.u_extrude_scale = pixelsToGLUnits;
+ circleShader.u_scale_with_map = false;
+ }
+
+ circleShader.u_devicepixelratio = frame.pixelRatio;
+ circleShader.u_color = properties.circleColor;
+ circleShader.u_radius = properties.circleRadius;
+ circleShader.u_blur = properties.circleBlur;
+ circleShader.u_opacity = properties.circleOpacity;
+
+ bucket.drawCircles(circleShader, store);
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_clipping.cpp b/src/mbgl/renderer/painter_clipping.cpp
index e6ce1a040e..7cb8e01c57 100644
--- a/src/mbgl/renderer/painter_clipping.cpp
+++ b/src/mbgl/renderer/painter_clipping.cpp
@@ -1,20 +1,24 @@
#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/style/source.hpp>
-#include <mbgl/shader/plain_shader.hpp>
+#include <mbgl/shader/shaders.hpp>
#include <mbgl/util/clip_id.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/gl/debugging.hpp>
-using namespace mbgl;
+namespace mbgl {
-void Painter::drawClippingMasks(const std::map<UnwrappedTileID, ClipID>& stencils) {
+void Painter::drawClippingMasks(PaintParameters& parameters, const std::map<UnwrappedTileID, ClipID>& stencils) {
MBGL_DEBUG_GROUP("clipping masks");
+ auto& plainShader = parameters.shaders.plain;
+ auto& arrayCoveringPlain = parameters.shaders.coveringPlainArray;
+
mat4 matrix;
const GLuint mask = 0b11111111;
- config.program = plainShader->getID();
+ config.program = plainShader.getID();
config.stencilOp.reset();
config.stencilTest = GL_TRUE;
config.depthTest = GL_FALSE;
@@ -22,7 +26,7 @@ void Painter::drawClippingMasks(const std::map<UnwrappedTileID, ClipID>& stencil
config.colorMask = { GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE };
config.stencilMask = mask;
- coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET_0, store);
+ arrayCoveringPlain.bind(plainShader, tileStencilBuffer, BUFFER_OFFSET_0, store);
for (const auto& stencil : stencils) {
const auto& id = stencil.first;
@@ -31,10 +35,12 @@ void Painter::drawClippingMasks(const std::map<UnwrappedTileID, ClipID>& stencil
MBGL_DEBUG_GROUP(std::string{ "mask: " } + util::toString(id));
state.matrixFor(matrix, id);
matrix::multiply(matrix, projMatrix, matrix);
- plainShader->u_matrix = matrix;
+ plainShader.u_matrix = matrix;
const GLint ref = (GLint)(clip.reference.to_ulong());
config.stencilFunc = { GL_ALWAYS, ref, mask };
MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()));
}
}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp
index b55a3c1628..8bb8e9d646 100644
--- a/src/mbgl/renderer/painter_debug.cpp
+++ b/src/mbgl/renderer/painter_debug.cpp
@@ -1,22 +1,23 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/debug_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/tile/tile.hpp>
-#include <mbgl/tile/tile_data.hpp>
-#include <mbgl/shader/plain_shader.hpp>
+#include <mbgl/shader/shaders.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/gl/debugging.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/gl_values.hpp>
#include <mbgl/gl/gl_helper.hpp>
+#include <mbgl/util/color.hpp>
-using namespace mbgl;
+namespace mbgl {
-void Painter::renderTileDebug(const Tile& tile) {
+void Painter::renderTileDebug(const RenderTile& tile) {
MBGL_DEBUG_GROUP(std::string { "debug " } + util::toString(tile.id));
if (frame.debugOptions != MapDebugOptions::NoDebug) {
setClipping(tile.clip);
if (frame.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) {
- renderDebugText(tile.data, tile.matrix);
+ renderDebugText(tile.tile, tile.matrix);
}
if (frame.debugOptions & MapDebugOptions::TileBorders) {
renderDebugFrame(tile.matrix);
@@ -24,39 +25,41 @@ void Painter::renderTileDebug(const Tile& tile) {
}
}
-void Painter::renderDebugText(TileData& tileData, const mat4 &matrix) {
+void Painter::renderDebugText(Tile& tile, const mat4 &matrix) {
MBGL_DEBUG_GROUP("debug text");
config.depthTest = GL_FALSE;
- if (!tileData.debugBucket || tileData.debugBucket->renderable != tileData.isRenderable() ||
- tileData.debugBucket->complete != tileData.isComplete() ||
- !(tileData.debugBucket->modified == tileData.modified) ||
- !(tileData.debugBucket->expires == tileData.expires) ||
- tileData.debugBucket->debugMode != frame.debugOptions) {
- tileData.debugBucket = std::make_unique<DebugBucket>(
- tileData.id, tileData.isRenderable(), tileData.isComplete(), tileData.modified,
- tileData.expires, frame.debugOptions);
+ if (!tile.debugBucket || tile.debugBucket->renderable != tile.isRenderable() ||
+ tile.debugBucket->complete != tile.isComplete() ||
+ !(tile.debugBucket->modified == tile.modified) ||
+ !(tile.debugBucket->expires == tile.expires) ||
+ tile.debugBucket->debugMode != frame.debugOptions) {
+ tile.debugBucket = std::make_unique<DebugBucket>(
+ tile.id, tile.isRenderable(), tile.isComplete(), tile.modified,
+ tile.expires, frame.debugOptions);
}
- config.program = plainShader->getID();
- plainShader->u_matrix = matrix;
+ auto& plainShader = shaders->plain;
+ config.program = plainShader.getID();
+ plainShader.u_matrix = matrix;
+ plainShader.u_opacity = 1.0f;
// Draw white outline
- plainShader->u_color = {{ 1.0f, 1.0f, 1.0f, 1.0f }};
+ plainShader.u_color = Color::white();
config.lineWidth = 4.0f * frame.pixelRatio;
- tileData.debugBucket->drawLines(*plainShader, store);
+ tile.debugBucket->drawLines(plainShader, store);
#ifndef GL_ES_VERSION_2_0
// Draw line "end caps"
MBGL_CHECK_ERROR(glPointSize(2));
- tileData.debugBucket->drawPoints(*plainShader, store);
+ tile.debugBucket->drawPoints(plainShader, store);
#endif
// Draw black text.
- plainShader->u_color = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
+ plainShader.u_color = Color::black();
config.lineWidth = 2.0f * frame.pixelRatio;
- tileData.debugBucket->drawLines(*plainShader, store);
+ tile.debugBucket->drawLines(plainShader, store);
config.depthFunc.reset();
config.depthTest = GL_TRUE;
@@ -72,16 +75,19 @@ void Painter::renderDebugFrame(const mat4 &matrix) {
config.stencilOp.reset();
config.stencilTest = GL_TRUE;
- config.program = plainShader->getID();
- plainShader->u_matrix = matrix;
+ auto& plainShader = shaders->plain;
+ config.program = plainShader.getID();
+ plainShader.u_matrix = matrix;
+ plainShader.u_opacity = 1.0f;
// draw tile outline
- tileBorderArray.bind(*plainShader, tileBorderBuffer, BUFFER_OFFSET_0, store);
- plainShader->u_color = {{ 1.0f, 0.0f, 0.0f, 1.0f }};
+ tileBorderArray.bind(plainShader, tileBorderBuffer, BUFFER_OFFSET_0, store);
+ plainShader.u_color = { 1.0f, 0.0f, 0.0f, 1.0f };
config.lineWidth = 4.0f * frame.pixelRatio;
MBGL_CHECK_ERROR(glDrawArrays(GL_LINE_STRIP, 0, (GLsizei)tileBorderBuffer.index()));
}
+#if defined(DEBUG)
void Painter::renderClipMasks() {
config.stencilTest = GL_FALSE;
config.depthTest = GL_FALSE;
@@ -117,3 +123,6 @@ void Painter::renderClipMasks() {
MBGL_CHECK_ERROR(glDrawPixels(fbSize[0], fbSize[1], GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels.get()));
#endif // GL_ES_VERSION_2_0
}
+#endif // defined(DEBUG)
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp
index 4c6ad1ba0f..9af2af9d10 100644
--- a/src/mbgl/renderer/painter_fill.cpp
+++ b/src/mbgl/renderer/painter_fill.cpp
@@ -1,201 +1,171 @@
#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/fill_layer_impl.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/shader/outline_shader.hpp>
-#include <mbgl/shader/outlinepattern_shader.hpp>
-#include <mbgl/shader/pattern_shader.hpp>
-#include <mbgl/shader/plain_shader.hpp>
+#include <mbgl/shader/shaders.hpp>
+#include <mbgl/util/convert.hpp>
namespace mbgl {
using namespace style;
-void Painter::renderFill(FillBucket& bucket,
+void Painter::renderFill(PaintParameters& parameters,
+ FillBucket& bucket,
const FillLayer& layer,
- const UnwrappedTileID& tileID,
- const mat4& matrix) {
+ const RenderTile& tile) {
const FillPaintProperties& properties = layer.impl->paint;
- mat4 vtxMatrix =
- translatedMatrix(matrix, properties.fillTranslate, tileID, properties.fillTranslateAnchor);
+ mat4 vertexMatrix = tile.translatedMatrix(properties.fillTranslate,
+ properties.fillTranslateAnchor,
+ state);
- Color fill_color = properties.fillColor;
+ Color fillColor = properties.fillColor;
float opacity = properties.fillOpacity;
- Color stroke_color = properties.fillOutlineColor;
- if (stroke_color[3] < 0) {
- stroke_color = fill_color;
- }
+ const bool isOutlineColorDefined = !properties.fillOutlineColor.isUndefined();
+ Color strokeColor = isOutlineColorDefined? properties.fillOutlineColor : fillColor;
+
+ auto worldSize = util::convert<GLfloat>(frame.framebufferSize);
bool pattern = !properties.fillPattern.value.from.empty();
- bool outline = properties.fillAntialias && !pattern && stroke_color != fill_color;
- bool fringeline = properties.fillAntialias && !pattern && stroke_color == fill_color;
-
- bool wireframe = frame.debugOptions & MapDebugOptions::Wireframe;
- if (wireframe) {
- fill_color = {{ 1.0f, 1.0f, 1.0f, 1.0f }};
- stroke_color = {{ 1.0f, 1.0f, 1.0f, 1.0f }};
- opacity = 1.0f;
- pattern = false;
- outline = true;
- fringeline = true;
- }
+ bool outline = properties.fillAntialias && !pattern && isOutlineColorDefined;
+ bool fringeline = properties.fillAntialias && !pattern && !isOutlineColorDefined;
config.stencilOp.reset();
config.stencilTest = GL_TRUE;
config.depthFunc.reset();
config.depthTest = GL_TRUE;
config.depthMask = GL_TRUE;
+ config.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio!
+
+ auto& outlineShader = parameters.shaders.outline;
+ auto& patternShader = parameters.shaders.pattern;
+ auto& outlinePatternShader = parameters.shaders.outlinePattern;
+ auto& plainShader = parameters.shaders.plain;
// Because we're drawing top-to-bottom, and we update the stencil mask
// befrom, we have to draw the outline first (!)
if (outline && pass == RenderPass::Translucent) {
- config.program = outlineShader->getID();
- outlineShader->u_matrix = vtxMatrix;
- config.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio!
+ config.program = outlineShader.getID();
+ outlineShader.u_matrix = vertexMatrix;
- outlineShader->u_outline_color = stroke_color;
- outlineShader->u_opacity = opacity;
+ outlineShader.u_outline_color = strokeColor;
+ outlineShader.u_opacity = opacity;
// Draw the entire line
- outlineShader->u_world = {{
- static_cast<float>(frame.framebufferSize[0]),
- static_cast<float>(frame.framebufferSize[1])
- }};
- setDepthSublayer(0);
- bucket.drawVertices(*outlineShader, store);
+ outlineShader.u_world = worldSize;
+ if (isOutlineColorDefined) {
+ // If we defined a different color for the fill outline, we are
+ // going to ignore the bits in 0x07 and just care about the global
+ // clipping mask.
+ setDepthSublayer(2); // OK
+ } else {
+ // Otherwise, we only want to drawFill the antialiased parts that are
+ // *outside* the current shape. This is important in case the fill
+ // or stroke color is translucent. If we wouldn't clip to outside
+ // the current shape, some pixels from the outline stroke overlapped
+ // the (non-antialiased) fill.
+ setDepthSublayer(0); // OK
+ }
+ bucket.drawVertices(outlineShader, store, isOverdraw());
}
if (pattern) {
- optional<SpriteAtlasPosition> posA = spriteAtlas->getPosition(properties.fillPattern.value.from, true);
- optional<SpriteAtlasPosition> posB = spriteAtlas->getPosition(properties.fillPattern.value.to, true);
+ optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition(properties.fillPattern.value.from, true);
+ optional<SpriteAtlasPosition> imagePosB = spriteAtlas->getPosition(properties.fillPattern.value.to, true);
// Image fill.
- if (pass == RenderPass::Translucent && posA && posB) {
- config.program = patternShader->getID();
- patternShader->u_matrix = vtxMatrix;
- patternShader->u_pattern_tl_a = (*posA).tl;
- patternShader->u_pattern_br_a = (*posA).br;
- patternShader->u_pattern_tl_b = (*posB).tl;
- patternShader->u_pattern_br_b = (*posB).br;
- patternShader->u_opacity = properties.fillOpacity;
- patternShader->u_image = 0;
- patternShader->u_mix = properties.fillPattern.value.t;
-
- std::array<int, 2> imageSizeScaledA = {{
- (int)((*posA).size[0] * properties.fillPattern.value.fromScale),
- (int)((*posA).size[1] * properties.fillPattern.value.fromScale)
- }};
- std::array<int, 2> imageSizeScaledB = {{
- (int)((*posB).size[0] * properties.fillPattern.value.toScale),
- (int)((*posB).size[1] * properties.fillPattern.value.toScale)
- }};
-
- patternShader->u_patternscale_a = {
- { 1.0f / tileID.pixelsToTileUnits(imageSizeScaledA[0], state.getIntegerZoom()),
- 1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[1], state.getIntegerZoom()) }
- };
- patternShader->u_patternscale_b = {
- { 1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[0], state.getIntegerZoom()),
- 1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[1], state.getIntegerZoom()) }
- };
-
- float offsetAx = (std::fmod(util::tileSize, imageSizeScaledA[0]) * tileID.canonical.x) /
- (float)imageSizeScaledA[0];
- float offsetAy = (std::fmod(util::tileSize, imageSizeScaledA[1]) * tileID.canonical.y) /
- (float)imageSizeScaledA[1];
-
- float offsetBx = (std::fmod(util::tileSize, imageSizeScaledB[0]) * tileID.canonical.x) /
- (float)imageSizeScaledB[0];
- float offsetBy = (std::fmod(util::tileSize, imageSizeScaledB[1]) * tileID.canonical.y) /
- (float)imageSizeScaledB[1];
-
- patternShader->u_offset_a = std::array<float, 2>{{offsetAx, offsetAy}};
- patternShader->u_offset_b = std::array<float, 2>{{offsetBx, offsetBy}};
-
- config.activeTexture = GL_TEXTURE0;
- spriteAtlas->bind(true, store);
+ if (pass == RenderPass::Translucent && imagePosA && imagePosB) {
+ config.program = patternShader.getID();
+ patternShader.u_matrix = vertexMatrix;
+ patternShader.u_pattern_tl_a = imagePosA->tl;
+ patternShader.u_pattern_br_a = imagePosA->br;
+ patternShader.u_pattern_tl_b = imagePosB->tl;
+ patternShader.u_pattern_br_b = imagePosB->br;
+ patternShader.u_opacity = properties.fillOpacity;
+ patternShader.u_image = 0;
+ patternShader.u_mix = properties.fillPattern.value.t;
+ patternShader.u_pattern_size_a = imagePosA->size;
+ patternShader.u_pattern_size_b = imagePosB->size;
+ patternShader.u_scale_a = properties.fillPattern.value.fromScale;
+ patternShader.u_scale_b = properties.fillPattern.value.toScale;
+ patternShader.u_tile_units_to_pixels = 1.0f / tile.id.pixelsToTileUnits(1.0f, state.getIntegerZoom());
+
+ GLint tileSizeAtNearestZoom = util::tileSize * state.zoomScale(state.getIntegerZoom() - tile.id.canonical.z);
+ GLint pixelX = tileSizeAtNearestZoom * (tile.id.canonical.x + tile.id.wrap * state.zoomScale(tile.id.canonical.z));
+ GLint pixelY = tileSizeAtNearestZoom * tile.id.canonical.y;
+ patternShader.u_pixel_coord_upper = {{ float(pixelX >> 16), float(pixelY >> 16) }};
+ patternShader.u_pixel_coord_lower = {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }};
+
+ spriteAtlas->bind(true, store, config, 0);
// Draw the actual triangles into the color & stencil buffer.
setDepthSublayer(0);
- bucket.drawElements(*patternShader, store);
-
- if (properties.fillAntialias && stroke_color == fill_color) {
- config.program = outlinePatternShader->getID();
- outlinePatternShader->u_matrix = vtxMatrix;
- config.lineWidth = 2.0f;
+ bucket.drawElements(patternShader, store, isOverdraw());
+
+ if (properties.fillAntialias && !isOutlineColorDefined) {
+ config.program = outlinePatternShader.getID();
+ outlinePatternShader.u_matrix = vertexMatrix;
+
+ outlinePatternShader.u_pattern_tl_a = imagePosA->tl;
+ outlinePatternShader.u_pattern_br_a = imagePosA->br;
+ outlinePatternShader.u_pattern_tl_b = imagePosB->tl;
+ outlinePatternShader.u_pattern_br_b = imagePosB->br;
+ outlinePatternShader.u_opacity = properties.fillOpacity;
+ outlinePatternShader.u_image = 0;
+ outlinePatternShader.u_mix = properties.fillPattern.value.t;
+ outlinePatternShader.u_pattern_size_a = imagePosA->size;
+ outlinePatternShader.u_pattern_size_b = imagePosB->size;
+ outlinePatternShader.u_scale_a = properties.fillPattern.value.fromScale;
+ outlinePatternShader.u_scale_b = properties.fillPattern.value.toScale;
+ outlinePatternShader.u_tile_units_to_pixels = 1.0f / tile.id.pixelsToTileUnits(1.0f, state.getIntegerZoom());
+ outlinePatternShader.u_pixel_coord_upper = {{ float(pixelX >> 16), float(pixelY >> 16) }};
+ outlinePatternShader.u_pixel_coord_lower = {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }};
// Draw the entire line
- outlinePatternShader->u_world = {{
- static_cast<float>(frame.framebufferSize[0]),
- static_cast<float>(frame.framebufferSize[1])
- }};
-
- outlinePatternShader->u_pattern_tl_a = (*posA).tl;
- outlinePatternShader->u_pattern_br_a = (*posA).br;
- outlinePatternShader->u_pattern_tl_b = (*posB).tl;
- outlinePatternShader->u_pattern_br_b = (*posB).br;
- outlinePatternShader->u_opacity = properties.fillOpacity;
- outlinePatternShader->u_image = 0;
- outlinePatternShader->u_mix = properties.fillPattern.value.t;
-
- outlinePatternShader->u_patternscale_a = {{
- 1.0f / tileID.pixelsToTileUnits(imageSizeScaledA[0], state.getIntegerZoom()),
- 1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[1], state.getIntegerZoom())
- }};
- outlinePatternShader->u_patternscale_b = {{
- 1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[0], state.getIntegerZoom()),
- 1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[1], state.getIntegerZoom())
- }};
-
- outlinePatternShader->u_offset_a = std::array<float, 2>{{offsetAx, offsetAy}};
- outlinePatternShader->u_offset_b = std::array<float, 2>{{offsetBx, offsetBy}};
-
- config.activeTexture = GL_TEXTURE0;
- spriteAtlas->bind(true, store);
+ outlinePatternShader.u_world = worldSize;
+
+ spriteAtlas->bind(true, store, config, 0);
setDepthSublayer(2);
- bucket.drawVertices(*outlinePatternShader, store);
+ bucket.drawVertices(outlinePatternShader, store, isOverdraw());
}
}
- } else if (!wireframe) {
+ } else {
// No image fill.
- if ((fill_color[3] >= 1.0f && opacity >= 1.0f) == (pass == RenderPass::Opaque)) {
+ if ((fillColor.a >= 1.0f && opacity >= 1.0f) == (pass == RenderPass::Opaque)) {
// Only draw the fill when it's either opaque and we're drawing opaque
// fragments or when it's translucent and we're drawing translucent
// fragments
// Draw filling rectangle.
- config.program = plainShader->getID();
- plainShader->u_matrix = vtxMatrix;
- plainShader->u_color = fill_color;
- plainShader->u_opacity = opacity;
+ config.program = plainShader.getID();
+ plainShader.u_matrix = vertexMatrix;
+ plainShader.u_color = fillColor;
+ plainShader.u_opacity = opacity;
// Draw the actual triangles into the color & stencil buffer.
setDepthSublayer(1);
- bucket.drawElements(*plainShader, store);
+ bucket.drawElements(plainShader, store, isOverdraw());
}
}
// Because we're drawing top-to-bottom, and we update the stencil mask
// below, we have to draw the outline first (!)
if (fringeline && pass == RenderPass::Translucent) {
- config.program = outlineShader->getID();
- outlineShader->u_matrix = vtxMatrix;
- config.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio!
+ config.program = outlineShader.getID();
+ outlineShader.u_matrix = vertexMatrix;
- outlineShader->u_outline_color = fill_color;
- outlineShader->u_opacity = opacity;
+ outlineShader.u_outline_color = fillColor;
+ outlineShader.u_opacity = opacity;
// Draw the entire line
- outlineShader->u_world = {{
- static_cast<float>(frame.framebufferSize[0]),
- static_cast<float>(frame.framebufferSize[1])
- }};
+ outlineShader.u_world = worldSize;
setDepthSublayer(2);
- bucket.drawVertices(*outlineShader, store);
+ bucket.drawVertices(outlineShader, store, isOverdraw());
}
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp
index 26041a8165..ed1975f955 100644
--- a/src/mbgl/renderer/painter_line.cpp
+++ b/src/mbgl/renderer/painter_line.cpp
@@ -1,10 +1,10 @@
#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/line_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/style/layers/line_layer_impl.hpp>
-#include <mbgl/shader/line_shader.hpp>
-#include <mbgl/shader/linesdf_shader.hpp>
-#include <mbgl/shader/linepattern_shader.hpp>
+#include <mbgl/shader/shaders.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/util/mat2.hpp>
@@ -13,10 +13,10 @@ namespace mbgl {
using namespace style;
-void Painter::renderLine(LineBucket& bucket,
+void Painter::renderLine(PaintParameters& parameters,
+ LineBucket& bucket,
const LineLayer& layer,
- const UnwrappedTileID& tileID,
- const mat4& matrix) {
+ const RenderTile& tile) {
// Abort early.
if (pass == RenderPass::Opaque) return;
@@ -33,18 +33,11 @@ void Painter::renderLine(LineBucket& bucket,
// Retina devices need a smaller distance to avoid aliasing.
float antialiasing = 1.0 / frame.pixelRatio;
- bool wireframe = frame.debugOptions & MapDebugOptions::Wireframe;
-
float blur = properties.lineBlur + antialiasing;
- Color color = {{ 1.0f, 1.0f, 1.0f, 1.0f }};
- float opacity = 1.0f;
- if (!wireframe) {
- color = properties.lineColor;
- opacity = properties.lineOpacity;
- }
-
- const float ratio = 1.0 / tileID.pixelsToTileUnits(1.0, state.getZoom());
+ const Color color = properties.lineColor;
+ const float opacity = properties.lineOpacity;
+ const float ratio = 1.0 / tile.id.pixelsToTileUnits(1.0, state.getZoom());
mat2 antialiasingMatrix;
matrix::identity(antialiasingMatrix);
@@ -53,115 +46,117 @@ void Painter::renderLine(LineBucket& bucket,
// calculate how much longer the real world distance is at the top of the screen
// than at the middle of the screen.
- float topedgelength = std::sqrt(std::pow(state.getHeight(), 2) / 4 * (1 + std::pow(state.getAltitude(), 2)));
+ float topedgelength = std::sqrt(std::pow(state.getHeight(), 2.0f) / 4.0f * (1.0f + std::pow(state.getAltitude(), 2.0f)));
float x = state.getHeight() / 2.0f * std::tan(state.getPitch());
- float extra = (topedgelength + x) / topedgelength - 1;
+ float extra = (topedgelength + x) / topedgelength - 1.0f;
- mat4 vtxMatrix =
- translatedMatrix(matrix, properties.lineTranslate, tileID, properties.lineTranslateAnchor);
+ mat4 vtxMatrix = tile.translatedMatrix(properties.lineTranslate,
+ properties.lineTranslateAnchor,
+ state);
setDepthSublayer(0);
- if (!properties.lineDasharray.value.from.empty()) {
+ auto& linesdfShader = parameters.shaders.linesdf;
+ auto& linepatternShader = parameters.shaders.linepattern;
+ auto& lineShader = parameters.shaders.line;
- config.program = linesdfShader->getID();
+ if (!properties.lineDasharray.value.from.empty()) {
+ config.program = linesdfShader.getID();
- linesdfShader->u_matrix = vtxMatrix;
- linesdfShader->u_linewidth = properties.lineWidth / 2;
- linesdfShader->u_gapwidth = properties.lineGapWidth / 2;
- linesdfShader->u_antialiasing = antialiasing / 2;
- linesdfShader->u_ratio = ratio;
- linesdfShader->u_blur = blur;
- linesdfShader->u_color = color;
- linesdfShader->u_opacity = opacity;
+ linesdfShader.u_matrix = vtxMatrix;
+ linesdfShader.u_linewidth = properties.lineWidth / 2;
+ linesdfShader.u_gapwidth = properties.lineGapWidth / 2;
+ linesdfShader.u_antialiasing = antialiasing / 2;
+ linesdfShader.u_ratio = ratio;
+ linesdfShader.u_blur = blur;
+ linesdfShader.u_color = color;
+ linesdfShader.u_opacity = opacity;
- LinePatternPos posA = lineAtlas->getDashPosition(properties.lineDasharray.value.from, layout.lineCap == LineCapType::Round, store);
- LinePatternPos posB = lineAtlas->getDashPosition(properties.lineDasharray.value.to, layout.lineCap == LineCapType::Round, store);
+ LinePatternPos posA = lineAtlas->getDashPosition(properties.lineDasharray.value.from, layout.lineCap == LineCapType::Round);
+ LinePatternPos posB = lineAtlas->getDashPosition(properties.lineDasharray.value.to, layout.lineCap == LineCapType::Round);
const float widthA = posA.width * properties.lineDasharray.value.fromScale * layer.impl->dashLineWidth;
const float widthB = posB.width * properties.lineDasharray.value.toScale * layer.impl->dashLineWidth;
- float scaleXA = 1.0 / tileID.pixelsToTileUnits(widthA, state.getIntegerZoom());
+ float scaleXA = 1.0 / tile.id.pixelsToTileUnits(widthA, state.getIntegerZoom());
float scaleYA = -posA.height / 2.0;
- float scaleXB = 1.0 / tileID.pixelsToTileUnits(widthB, state.getIntegerZoom());
+ float scaleXB = 1.0 / tile.id.pixelsToTileUnits(widthB, state.getIntegerZoom());
float scaleYB = -posB.height / 2.0;
- linesdfShader->u_patternscale_a = {{ scaleXA, scaleYA }};
- linesdfShader->u_tex_y_a = posA.y;
- linesdfShader->u_patternscale_b = {{ scaleXB, scaleYB }};
- linesdfShader->u_tex_y_b = posB.y;
- linesdfShader->u_sdfgamma = lineAtlas->width / (std::min(widthA, widthB) * 256.0 * frame.pixelRatio) / 2;
- linesdfShader->u_mix = properties.lineDasharray.value.t;
- linesdfShader->u_extra = extra;
- linesdfShader->u_offset = -properties.lineOffset;
- linesdfShader->u_antialiasingmatrix = antialiasingMatrix;
+ linesdfShader.u_patternscale_a = {{ scaleXA, scaleYA }};
+ linesdfShader.u_tex_y_a = posA.y;
+ linesdfShader.u_patternscale_b = {{ scaleXB, scaleYB }};
+ linesdfShader.u_tex_y_b = posB.y;
+ linesdfShader.u_sdfgamma = lineAtlas->width / (std::min(widthA, widthB) * 256.0 * frame.pixelRatio) / 2;
+ linesdfShader.u_mix = properties.lineDasharray.value.t;
+ linesdfShader.u_extra = extra;
+ linesdfShader.u_offset = -properties.lineOffset;
+ linesdfShader.u_antialiasingmatrix = antialiasingMatrix;
- linesdfShader->u_image = 0;
- config.activeTexture = GL_TEXTURE0;
- lineAtlas->bind(store);
+ linesdfShader.u_image = 0;
+ lineAtlas->bind(store, config, 0);
- bucket.drawLineSDF(*linesdfShader, store);
+ bucket.drawLineSDF(linesdfShader, store, isOverdraw());
} else if (!properties.linePattern.value.from.empty()) {
optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition(properties.linePattern.value.from, true);
optional<SpriteAtlasPosition> imagePosB = spriteAtlas->getPosition(properties.linePattern.value.to, true);
-
+
if (!imagePosA || !imagePosB)
return;
- config.program = linepatternShader->getID();
+ config.program = linepatternShader.getID();
- linepatternShader->u_matrix = vtxMatrix;
- linepatternShader->u_linewidth = properties.lineWidth / 2;
- linepatternShader->u_gapwidth = properties.lineGapWidth / 2;
- linepatternShader->u_antialiasing = antialiasing / 2;
- linepatternShader->u_ratio = ratio;
- linepatternShader->u_blur = blur;
+ linepatternShader.u_matrix = vtxMatrix;
+ linepatternShader.u_linewidth = properties.lineWidth / 2;
+ linepatternShader.u_gapwidth = properties.lineGapWidth / 2;
+ linepatternShader.u_antialiasing = antialiasing / 2;
+ linepatternShader.u_ratio = ratio;
+ linepatternShader.u_blur = blur;
- linepatternShader->u_pattern_size_a = {{
- tileID.pixelsToTileUnits((*imagePosA).size[0] * properties.linePattern.value.fromScale, state.getIntegerZoom()),
+ linepatternShader.u_pattern_size_a = {{
+ tile.id.pixelsToTileUnits((*imagePosA).size[0] * properties.linePattern.value.fromScale, state.getIntegerZoom()),
(*imagePosA).size[1]
}};
- linepatternShader->u_pattern_tl_a = (*imagePosA).tl;
- linepatternShader->u_pattern_br_a = (*imagePosA).br;
+ linepatternShader.u_pattern_tl_a = (*imagePosA).tl;
+ linepatternShader.u_pattern_br_a = (*imagePosA).br;
- linepatternShader->u_pattern_size_b = {{
- tileID.pixelsToTileUnits((*imagePosB).size[0] * properties.linePattern.value.toScale, state.getIntegerZoom()),
+ linepatternShader.u_pattern_size_b = {{
+ tile.id.pixelsToTileUnits((*imagePosB).size[0] * properties.linePattern.value.toScale, state.getIntegerZoom()),
(*imagePosB).size[1]
}};
- linepatternShader->u_pattern_tl_b = (*imagePosB).tl;
- linepatternShader->u_pattern_br_b = (*imagePosB).br;
+ linepatternShader.u_pattern_tl_b = (*imagePosB).tl;
+ linepatternShader.u_pattern_br_b = (*imagePosB).br;
- linepatternShader->u_fade = properties.linePattern.value.t;
- linepatternShader->u_opacity = properties.lineOpacity;
- linepatternShader->u_extra = extra;
- linepatternShader->u_offset = -properties.lineOffset;
- linepatternShader->u_antialiasingmatrix = antialiasingMatrix;
+ linepatternShader.u_fade = properties.linePattern.value.t;
+ linepatternShader.u_opacity = properties.lineOpacity;
+ linepatternShader.u_extra = extra;
+ linepatternShader.u_offset = -properties.lineOffset;
+ linepatternShader.u_antialiasingmatrix = antialiasingMatrix;
- linepatternShader->u_image = 0;
- config.activeTexture = GL_TEXTURE0;
- spriteAtlas->bind(true, store);
+ linepatternShader.u_image = 0;
+ spriteAtlas->bind(true, store, config, 0);
- bucket.drawLinePatterns(*linepatternShader, store);
+ bucket.drawLinePatterns(linepatternShader, store, isOverdraw());
} else {
- config.program = lineShader->getID();
-
- lineShader->u_matrix = vtxMatrix;
- lineShader->u_linewidth = properties.lineWidth / 2;
- lineShader->u_gapwidth = properties.lineGapWidth / 2;
- lineShader->u_antialiasing = antialiasing / 2;
- lineShader->u_ratio = ratio;
- lineShader->u_blur = blur;
- lineShader->u_extra = extra;
- lineShader->u_offset = -properties.lineOffset;
- lineShader->u_antialiasingmatrix = antialiasingMatrix;
-
- lineShader->u_color = color;
- lineShader->u_opacity = opacity;
-
- bucket.drawLines(*lineShader, store);
+ config.program = lineShader.getID();
+
+ lineShader.u_matrix = vtxMatrix;
+ lineShader.u_linewidth = properties.lineWidth / 2;
+ lineShader.u_gapwidth = properties.lineGapWidth / 2;
+ lineShader.u_antialiasing = antialiasing / 2;
+ lineShader.u_ratio = ratio;
+ lineShader.u_blur = blur;
+ lineShader.u_extra = extra;
+ lineShader.u_offset = -properties.lineOffset;
+ lineShader.u_antialiasingmatrix = antialiasingMatrix;
+
+ lineShader.u_color = color;
+ lineShader.u_opacity = opacity;
+
+ bucket.drawLines(lineShader, store, isOverdraw());
}
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painter_raster.cpp
index cce71e8ce2..8f6a1ac27b 100644
--- a/src/mbgl/renderer/painter_raster.cpp
+++ b/src/mbgl/renderer/painter_raster.cpp
@@ -1,43 +1,53 @@
#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/renderer/raster_bucket.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
#include <mbgl/style/layers/raster_layer_impl.hpp>
-#include <mbgl/shader/raster_shader.hpp>
+#include <mbgl/shader/shaders.hpp>
namespace mbgl {
using namespace style;
-void Painter::renderRaster(RasterBucket& bucket,
+void Painter::renderRaster(PaintParameters& parameters,
+ RasterBucket& bucket,
const RasterLayer& layer,
- const UnwrappedTileID&,
- const mat4& matrix) {
+ const RenderTile& tile) {
if (pass != RenderPass::Translucent) return;
const RasterPaintProperties& properties = layer.impl->paint;
if (bucket.hasData()) {
- config.program = rasterShader->getID();
- rasterShader->u_matrix = matrix;
- rasterShader->u_buffer = 0;
- rasterShader->u_opacity = properties.rasterOpacity;
- rasterShader->u_brightness_low = properties.rasterBrightnessMin;
- rasterShader->u_brightness_high = properties.rasterBrightnessMax;
- rasterShader->u_saturation_factor = saturationFactor(properties.rasterSaturation);
- rasterShader->u_contrast_factor = contrastFactor(properties.rasterContrast);
- rasterShader->u_spin_weights = spinWeights(properties.rasterHueRotate);
+ auto& rasterShader = parameters.shaders.raster;
+ auto& rasterVAO = parameters.shaders.coveringRasterArray;
+
+ config.program = rasterShader.getID();
+ rasterShader.u_matrix = tile.matrix;
+ rasterShader.u_buffer_scale = 1.0f;
+ rasterShader.u_opacity0 = properties.rasterOpacity;
+ rasterShader.u_opacity1 = 0;
+
+ rasterShader.u_brightness_low = properties.rasterBrightnessMin;
+ rasterShader.u_brightness_high = properties.rasterBrightnessMax;
+ rasterShader.u_saturation_factor = saturationFactor(properties.rasterSaturation);
+ rasterShader.u_contrast_factor = contrastFactor(properties.rasterContrast);
+ rasterShader.u_spin_weights = spinWeights(properties.rasterHueRotate);
config.stencilTest = GL_FALSE;
- rasterShader->u_image = 0;
- config.activeTexture = GL_TEXTURE0;
+ rasterShader.u_image0 = 0; // GL_TEXTURE0
+ rasterShader.u_image1 = 1; // GL_TEXTURE1
+ rasterShader.u_tl_parent = {{ 0.0f, 0.0f }};
+ rasterShader.u_scale_parent = 1.0f;
config.depthFunc.reset();
config.depthTest = GL_TRUE;
config.depthMask = GL_FALSE;
setDepthSublayer(0);
- bucket.drawRaster(*rasterShader, tileStencilBuffer, coveringRasterArray, store);
+
+ bucket.drawRaster(rasterShader, rasterBoundsBuffer, rasterVAO, config, store);
}
}
@@ -69,4 +79,4 @@ std::array<float, 3> Painter::spinWeights(float spin) {
return spin_weights;
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp
index 3c453242ae..8599329842 100644
--- a/src/mbgl/renderer/painter_symbol.cpp
+++ b/src/mbgl/renderer/painter_symbol.cpp
@@ -1,12 +1,12 @@
#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/symbol_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/geometry/glyph_atlas.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/shader/sdf_shader.hpp>
-#include <mbgl/shader/icon_shader.hpp>
-#include <mbgl/shader/collision_box_shader.hpp>
+#include <mbgl/shader/shaders.hpp>
#include <mbgl/util/math.hpp>
#include <cmath>
@@ -15,16 +15,16 @@ namespace mbgl {
using namespace style;
-void Painter::renderSDF(SymbolBucket &bucket,
- const UnwrappedTileID &tileID,
- const mat4 &matrix,
+void Painter::renderSDF(SymbolBucket& bucket,
+ const RenderTile& tile,
float sdfFontSize,
std::array<float, 2> texsize,
SDFShader& sdfShader,
- void (SymbolBucket::*drawSDF)(SDFShader&, gl::ObjectStore&),
+ void (SymbolBucket::*drawSDF)(SDFShader&, gl::ObjectStore&, bool),
// Layout
- RotationAlignmentType rotationAlignment,
+ AlignmentType rotationAlignment,
+ AlignmentType pitchAlignment,
float layoutSize,
// Paint
@@ -37,39 +37,46 @@ void Painter::renderSDF(SymbolBucket &bucket,
TranslateAnchorType translateAnchor,
float paintSize)
{
- mat4 vtxMatrix = translatedMatrix(matrix, translate, tileID, translateAnchor);
+ mat4 vtxMatrix = tile.translatedMatrix(translate, translateAnchor, state);
// If layerStyle.size > bucket.info.fontSize then labels may collide
float fontSize = paintSize;
float fontScale = fontSize / sdfFontSize;
- float scale = fontScale;
- std::array<float, 2> exScale = extrudeScale;
- bool alignedWithMap = rotationAlignment == RotationAlignmentType::Map;
- float gammaScale = 1.0f;
+ bool rotateWithMap = rotationAlignment == AlignmentType::Map;
+ bool pitchWithMap = pitchAlignment == AlignmentType::Map;
- if (alignedWithMap) {
- scale *= tileID.pixelsToTileUnits(1, state.getZoom());
- exScale.fill(scale);
- gammaScale /= std::cos(state.getPitch());
+ std::array<float, 2> extrudeScale;
+ float gammaScale;
+
+ if (pitchWithMap) {
+ gammaScale = 1.0 / std::cos(state.getPitch());
+ extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom()) * fontScale);
} else {
- exScale = {{ exScale[0] * scale, exScale[1] * scale }};
+ gammaScale = 1.0;
+ extrudeScale = {{
+ pixelsToGLUnits[0] * fontScale * state.getAltitude(),
+ pixelsToGLUnits[1] * fontScale * state.getAltitude()
+ }};
}
config.program = sdfShader.getID();
sdfShader.u_matrix = vtxMatrix;
- sdfShader.u_extrude_scale = exScale;
+ sdfShader.u_extrude_scale = extrudeScale;
sdfShader.u_texsize = texsize;
- sdfShader.u_skewed = alignedWithMap;
+ sdfShader.u_rotate_with_map = rotateWithMap;
+ sdfShader.u_pitch_with_map = pitchWithMap;
sdfShader.u_texture = 0;
+ sdfShader.u_pitch = state.getPitch() * util::DEG2RAD;
+ sdfShader.u_bearing = -1.0f * state.getAngle();
+ sdfShader.u_aspect_ratio = (state.getWidth() * 1.0f) / (state.getHeight() * 1.0f);
// adjust min/max zooms for variable font sies
float zoomAdjust = std::log(fontSize / layoutSize) / std::log(2);
sdfShader.u_zoom = (state.getZoom() - zoomAdjust) * 10; // current zoom level
- config.activeTexture = GL_TEXTURE1;
- frameHistory.bind(store);
+ frameHistory.bind(store, config, 1);
sdfShader.u_fadetexture = 1;
// The default gamma value has to be adjust for the current pixelratio so that we're not
@@ -82,32 +89,32 @@ void Painter::renderSDF(SymbolBucket &bucket,
// We're drawing in the translucent pass which is bottom-to-top, so we need
// to draw the halo first.
- if (haloColor[3] > 0.0f && haloWidth > 0.0f) {
+ if (haloColor.a > 0.0f && haloWidth > 0.0f) {
sdfShader.u_gamma = (haloBlur * blurOffset / fontScale / sdfPx + gamma) * gammaScale;
sdfShader.u_color = haloColor;
sdfShader.u_opacity = opacity;
sdfShader.u_buffer = (haloOffset - haloWidth / fontScale) / sdfPx;
setDepthSublayer(0);
- (bucket.*drawSDF)(sdfShader, store);
+ (bucket.*drawSDF)(sdfShader, store, isOverdraw());
}
// Then, we draw the text/icon over the halo
- if (color[3] > 0.0f) {
+ if (color.a > 0.0f) {
sdfShader.u_gamma = gamma * gammaScale;
sdfShader.u_color = color;
sdfShader.u_opacity = opacity;
sdfShader.u_buffer = (256.0f - 64.0f) / 256.0f;
setDepthSublayer(1);
- (bucket.*drawSDF)(sdfShader, store);
+ (bucket.*drawSDF)(sdfShader, store, isOverdraw());
}
}
-void Painter::renderSymbol(SymbolBucket& bucket,
+void Painter::renderSymbol(PaintParameters& parameters,
+ SymbolBucket& bucket,
const SymbolLayer& layer,
- const UnwrappedTileID& tileID,
- const mat4& matrix) {
+ const RenderTile& tile) {
// Abort early.
if (pass == RenderPass::Opaque) {
return;
@@ -135,7 +142,7 @@ void Painter::renderSymbol(SymbolBucket& bucket,
}
if (bucket.hasIconData()) {
- if (layout.iconRotationAlignment == RotationAlignmentType::Map) {
+ if (layout.iconRotationAlignment == AlignmentType::Map) {
config.depthFunc.reset();
config.depthTest = GL_TRUE;
} else {
@@ -145,7 +152,7 @@ void Painter::renderSymbol(SymbolBucket& bucket,
bool sdf = bucket.sdfIcons;
const float angleOffset =
- layout.iconRotationAlignment == RotationAlignmentType::Map
+ layout.iconRotationAlignment == AlignmentType::Map
? state.getAngle()
: 0;
@@ -154,19 +161,20 @@ void Painter::renderSymbol(SymbolBucket& bucket,
SpriteAtlas* activeSpriteAtlas = layer.impl->spriteAtlas;
const bool iconScaled = fontScale != 1 || frame.pixelRatio != activeSpriteAtlas->getPixelRatio() || bucket.iconsNeedLinear;
- const bool iconTransformed = layout.iconRotationAlignment == RotationAlignmentType::Map || angleOffset != 0 || state.getPitch() != 0;
- config.activeTexture = GL_TEXTURE0;
- activeSpriteAtlas->bind(sdf || state.isChanging() || iconScaled || iconTransformed, store);
+ const bool iconTransformed = layout.iconRotationAlignment == AlignmentType::Map || angleOffset != 0 || state.getPitch() != 0;
+ activeSpriteAtlas->bind(sdf || state.isChanging() || iconScaled || iconTransformed, store, config, 0);
if (sdf) {
renderSDF(bucket,
- tileID,
- matrix,
+ tile,
1.0f,
{{ float(activeSpriteAtlas->getWidth()) / 4.0f, float(activeSpriteAtlas->getHeight()) / 4.0f }},
- *sdfIconShader,
+ parameters.shaders.sdfIcon,
&SymbolBucket::drawIcons,
layout.iconRotationAlignment,
+ // icon-pitch-alignment is not yet implemented
+ // and we simply inherit the rotation alignment
+ layout.iconRotationAlignment,
layout.iconSize,
paint.iconOpacity,
paint.iconColor,
@@ -177,59 +185,62 @@ void Painter::renderSymbol(SymbolBucket& bucket,
paint.iconTranslateAnchor,
layer.impl->iconSize);
} else {
- mat4 vtxMatrix =
- translatedMatrix(matrix, paint.iconTranslate, tileID, paint.iconTranslateAnchor);
+ mat4 vtxMatrix = tile.translatedMatrix(paint.iconTranslate,
+ paint.iconTranslateAnchor,
+ state);
+
+ std::array<float, 2> extrudeScale;
- float scale = fontScale;
- std::array<float, 2> exScale = extrudeScale;
- const bool alignedWithMap = layout.iconRotationAlignment == RotationAlignmentType::Map;
+ const bool alignedWithMap = layout.iconRotationAlignment == AlignmentType::Map;
if (alignedWithMap) {
- scale *= tileID.pixelsToTileUnits(1, state.getZoom());
- exScale.fill(scale);
+ extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom()) * fontScale);
} else {
- exScale = {{ exScale[0] * scale, exScale[1] * scale }};
+ extrudeScale = {{
+ pixelsToGLUnits[0] * fontScale * state.getAltitude(),
+ pixelsToGLUnits[1] * fontScale * state.getAltitude()
+ }};
}
- config.program = iconShader->getID();
- iconShader->u_matrix = vtxMatrix;
- iconShader->u_extrude_scale = exScale;
- iconShader->u_texsize = {{ float(activeSpriteAtlas->getWidth()) / 4.0f, float(activeSpriteAtlas->getHeight()) / 4.0f }};
- iconShader->u_skewed = alignedWithMap;
- iconShader->u_texture = 0;
+ auto& iconShader = parameters.shaders.icon;
+
+ config.program = iconShader.getID();
+ iconShader.u_matrix = vtxMatrix;
+ iconShader.u_extrude_scale = extrudeScale;
+ iconShader.u_texsize = {{ float(activeSpriteAtlas->getWidth()) / 4.0f, float(activeSpriteAtlas->getHeight()) / 4.0f }};
+ iconShader.u_rotate_with_map = alignedWithMap;
+ iconShader.u_texture = 0;
// adjust min/max zooms for variable font sies
float zoomAdjust = std::log(fontSize / layout.iconSize) / std::log(2);
- iconShader->u_zoom = (state.getZoom() - zoomAdjust) * 10; // current zoom level
- iconShader->u_opacity = paint.iconOpacity;
+ iconShader.u_zoom = (state.getZoom() - zoomAdjust) * 10; // current zoom level
+ iconShader.u_opacity = paint.iconOpacity;
- config.activeTexture = GL_TEXTURE1;
- frameHistory.bind(store);
- iconShader->u_fadetexture = 1;
+ frameHistory.bind(store, config, 1);
+ iconShader.u_fadetexture = 1;
setDepthSublayer(0);
- bucket.drawIcons(*iconShader, store);
+ bucket.drawIcons(iconShader, store, isOverdraw());
}
}
if (bucket.hasTextData()) {
- if (layout.textRotationAlignment == RotationAlignmentType::Map) {
+ if (layout.textRotationAlignment == AlignmentType::Map) {
config.depthFunc.reset();
config.depthTest = GL_TRUE;
} else {
config.depthTest = GL_FALSE;
}
- config.activeTexture = GL_TEXTURE0;
- glyphAtlas->bind(store);
+ glyphAtlas->bind(store, config, 0);
renderSDF(bucket,
- tileID,
- matrix,
+ tile,
24.0f,
{{ float(glyphAtlas->width) / 4, float(glyphAtlas->height) / 4 }},
- *sdfGlyphShader,
+ parameters.shaders.sdfGlyph,
&SymbolBucket::drawGlyphs,
layout.textRotationAlignment,
+ layout.textPitchAlignment,
layout.textSize,
paint.textOpacity,
paint.textColor,
@@ -245,20 +256,19 @@ void Painter::renderSymbol(SymbolBucket& bucket,
config.stencilOp.reset();
config.stencilTest = GL_TRUE;
- config.program = collisionBoxShader->getID();
- collisionBoxShader->u_matrix = matrix;
+ auto& collisionBoxShader = shaders->collisionBox;
+ config.program = collisionBoxShader.getID();
+ collisionBoxShader.u_matrix = tile.matrix;
// TODO: This was the overscaled z instead of the canonical z.
- collisionBoxShader->u_scale = std::pow(2, state.getZoom() - tileID.canonical.z);
- collisionBoxShader->u_zoom = state.getZoom() * 10;
- collisionBoxShader->u_maxzoom = (tileID.canonical.z + 1) * 10;
+ collisionBoxShader.u_scale = std::pow(2, state.getZoom() - tile.id.canonical.z);
+ collisionBoxShader.u_zoom = state.getZoom() * 10;
+ collisionBoxShader.u_maxzoom = (tile.id.canonical.z + 1) * 10;
config.lineWidth = 1.0f;
setDepthSublayer(0);
- bucket.drawCollisionBoxes(*collisionBoxShader, store);
+ bucket.drawCollisionBoxes(collisionBoxShader, store);
}
-
- config.activeTexture = GL_TEXTURE0;
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/raster_bucket.cpp b/src/mbgl/renderer/raster_bucket.cpp
index 39f8dacd92..58647a330d 100644
--- a/src/mbgl/renderer/raster_bucket.cpp
+++ b/src/mbgl/renderer/raster_bucket.cpp
@@ -7,32 +7,33 @@ namespace mbgl {
using namespace style;
-RasterBucket::RasterBucket(gl::TexturePool& texturePool)
-: raster(texturePool) {
-}
-
-void RasterBucket::upload(gl::ObjectStore& store) {
+void RasterBucket::upload(gl::ObjectStore& store, gl::Config& config) {
if (hasData()) {
- raster.upload(store);
+ raster.upload(store, config, 0);
uploaded = true;
}
}
void RasterBucket::render(Painter& painter,
+ PaintParameters& parameters,
const Layer& layer,
- const UnwrappedTileID& tileID,
- const mat4& matrix) {
- painter.renderRaster(*this, *layer.as<RasterLayer>(), tileID, matrix);
+ const RenderTile& tile) {
+ painter.renderRaster(parameters, *this, *layer.as<RasterLayer>(), tile);
}
void RasterBucket::setImage(PremultipliedImage image) {
raster.load(std::move(image));
}
-void RasterBucket::drawRaster(RasterShader& shader, StaticVertexBuffer &vertices, VertexArrayObject &array, gl::ObjectStore& store) {
- raster.bind(true, store);
+void RasterBucket::drawRaster(RasterShader& shader,
+ StaticRasterVertexBuffer& vertices,
+ VertexArrayObject& array,
+ gl::Config& config,
+ gl::ObjectStore& store) {
+ raster.bind(store, config, 0, Raster::Scaling::Linear);
+ raster.bind(store, config, 1, Raster::Scaling::Linear);
array.bind(shader, vertices, BUFFER_OFFSET_0, store);
- MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertices.index()));
+ MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)vertices.index()));
}
bool RasterBucket::hasData() const {
@@ -43,4 +44,4 @@ bool RasterBucket::needsClipping() const {
return false;
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/raster_bucket.hpp b/src/mbgl/renderer/raster_bucket.hpp
index 93331755fb..e212b9ecea 100644
--- a/src/mbgl/renderer/raster_bucket.hpp
+++ b/src/mbgl/renderer/raster_bucket.hpp
@@ -2,25 +2,24 @@
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/util/raster.hpp>
+#include <mbgl/gl/gl_config.hpp>
namespace mbgl {
class RasterShader;
-class StaticVertexBuffer;
+class StaticRasterVertexBuffer;
class VertexArrayObject;
class RasterBucket : public Bucket {
public:
- RasterBucket(gl::TexturePool&);
-
- void upload(gl::ObjectStore&) override;
- void render(Painter&, const style::Layer&, const UnwrappedTileID&, const mat4&) override;
+ void upload(gl::ObjectStore&, gl::Config&) override;
+ void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
bool hasData() const override;
bool needsClipping() const override;
void setImage(PremultipliedImage);
- void drawRaster(RasterShader&, StaticVertexBuffer&, VertexArrayObject&, gl::ObjectStore&);
+ void drawRaster(RasterShader&, StaticRasterVertexBuffer&, VertexArrayObject&, gl::Config&, gl::ObjectStore&);
Raster raster;
};
diff --git a/src/mbgl/renderer/render_item.hpp b/src/mbgl/renderer/render_item.hpp
index 6c97b66bd1..82ea897047 100644
--- a/src/mbgl/renderer/render_item.hpp
+++ b/src/mbgl/renderer/render_item.hpp
@@ -7,30 +7,30 @@
namespace mbgl {
-class Tile;
+class RenderTile;
class Bucket;
namespace style {
class Layer;
class Source;
-}
+} // namespace style
class RenderItem {
public:
RenderItem(const style::Layer& layer_,
- const Tile* tile_ = nullptr,
+ const RenderTile* tile_ = nullptr,
Bucket* bucket_ = nullptr)
: tile(tile_), bucket(bucket_), layer(layer_) {
}
- const Tile* const tile;
+ const RenderTile* const tile;
Bucket* const bucket;
const style::Layer& layer;
};
class RenderData {
public:
- Color backgroundColor = {{ 0, 0, 0, 0 }};
+ Color backgroundColor;
std::set<style::Source*> sources;
std::vector<RenderItem> order;
};
diff --git a/src/mbgl/renderer/render_pass.hpp b/src/mbgl/renderer/render_pass.hpp
index e31383b7cf..93edac2039 100644
--- a/src/mbgl/renderer/render_pass.hpp
+++ b/src/mbgl/renderer/render_pass.hpp
@@ -12,16 +12,16 @@ enum class RenderPass : uint8_t {
Translucent = 1 << 1,
};
-constexpr inline RenderPass operator|(RenderPass a, RenderPass b) {
- return static_cast<RenderPass>(mbgl::underlying_type(a) | mbgl::underlying_type(b));
+constexpr RenderPass operator|(RenderPass a, RenderPass b) {
+ return RenderPass(mbgl::underlying_type(a) | mbgl::underlying_type(b));
}
-inline RenderPass operator|=(RenderPass& a, RenderPass b) {
+constexpr RenderPass& operator|=(RenderPass& a, RenderPass b) {
return (a = a | b);
}
-constexpr inline RenderPass operator&(RenderPass a, RenderPass b) {
- return static_cast<RenderPass>(mbgl::underlying_type(a) & mbgl::underlying_type(b));
+constexpr RenderPass operator&(RenderPass a, RenderPass b) {
+ return RenderPass(mbgl::underlying_type(a) & mbgl::underlying_type(b));
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp
new file mode 100644
index 0000000000..5c7c491be0
--- /dev/null
+++ b/src/mbgl/renderer/render_tile.cpp
@@ -0,0 +1,34 @@
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/map/transform_state.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+mat4 RenderTile::translatedMatrix(const std::array<float, 2>& translation,
+ TranslateAnchorType anchor,
+ const TransformState& state) const {
+ if (translation[0] == 0 && translation[1] == 0) {
+ return matrix;
+ }
+
+ mat4 vtxMatrix;
+
+ if (anchor == TranslateAnchorType::Viewport) {
+ const double sin_a = std::sin(-state.getAngle());
+ const double cos_a = std::cos(-state.getAngle());
+ matrix::translate(vtxMatrix, matrix,
+ id.pixelsToTileUnits(translation[0] * cos_a - translation[1] * sin_a, state.getZoom()),
+ id.pixelsToTileUnits(translation[0] * sin_a + translation[1] * cos_a, state.getZoom()),
+ 0);
+ } else {
+ matrix::translate(vtxMatrix, matrix,
+ id.pixelsToTileUnits(translation[0], state.getZoom()),
+ id.pixelsToTileUnits(translation[1], state.getZoom()),
+ 0);
+ }
+
+ return vtxMatrix;
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp
new file mode 100644
index 0000000000..82b60a66c7
--- /dev/null
+++ b/src/mbgl/renderer/render_tile.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <mbgl/tile/tile_id.hpp>
+#include <mbgl/util/mat4.hpp>
+#include <mbgl/util/ptr.hpp>
+#include <mbgl/util/clip_id.hpp>
+#include <mbgl/style/types.hpp>
+
+#include <array>
+
+namespace mbgl {
+
+class Tile;
+class TransformState;
+
+class RenderTile {
+public:
+ RenderTile(UnwrappedTileID id_, Tile& tile_) : id(std::move(id_)), tile(tile_) {}
+ RenderTile(const RenderTile&) = delete;
+ RenderTile(RenderTile&&) = default;
+ RenderTile& operator=(const RenderTile&) = delete;
+ RenderTile& operator=(RenderTile&&) = default;
+
+ const UnwrappedTileID id;
+ Tile& tile;
+ ClipID clip;
+ mat4 matrix;
+
+ mat4 translatedMatrix(const std::array<float, 2>& translate,
+ style::TranslateAnchorType anchor,
+ const TransformState&) const;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp
index f4e55432c1..008372b2bf 100644
--- a/src/mbgl/renderer/symbol_bucket.cpp
+++ b/src/mbgl/renderer/symbol_bucket.cpp
@@ -1,7 +1,7 @@
#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/sprite/sprite_store.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
@@ -51,29 +51,29 @@ SymbolInstance::SymbolInstance(Anchor& anchor, const GeometryCoordinates& line,
// Create the quad used for rendering the icon.
iconQuads(addToBuffers && shapedIcon ?
- getIconQuads(anchor, shapedIcon, line, layout, iconAlongLine) :
+ getIconQuads(anchor, shapedIcon, line, layout, iconAlongLine, shapedText) :
SymbolQuads()),
// Create the collision features that will be used to check whether this symbol instance can be placed
textCollisionFeature(line, anchor, shapedText, textBoxScale, textPadding, textAlongLine, indexedFeature),
iconCollisionFeature(line, anchor, shapedIcon, iconBoxScale, iconPadding, iconAlongLine, indexedFeature)
- {};
+ {}
-SymbolBucket::SymbolBucket(uint32_t overscaling_, float zoom_, const MapMode mode_, const std::string& bucketName_, const std::string& sourceLayerName_)
+SymbolBucket::SymbolBucket(uint32_t overscaling_, float zoom_, const MapMode mode_, std::string bucketName_, std::string sourceLayerName_)
: overscaling(overscaling_),
zoom(zoom_),
tileSize(util::tileSize * overscaling_),
tilePixelRatio(float(util::EXTENT) / tileSize),
mode(mode_),
- bucketName(bucketName_),
- sourceLayerName(sourceLayerName_) {}
+ bucketName(std::move(bucketName_)),
+ sourceLayerName(std::move(sourceLayerName_)) {}
SymbolBucket::~SymbolBucket() {
// Do not remove. header file only contains forward definitions to unique pointers.
}
-void SymbolBucket::upload(gl::ObjectStore& store) {
+void SymbolBucket::upload(gl::ObjectStore& store, gl::Config&) {
if (hasTextData()) {
renderData->text.vertices.upload(store);
renderData->text.triangles.upload(store);
@@ -87,10 +87,10 @@ void SymbolBucket::upload(gl::ObjectStore& store) {
}
void SymbolBucket::render(Painter& painter,
+ PaintParameters& parameters,
const Layer& layer,
- const UnwrappedTileID& tileID,
- const mat4& matrix) {
- painter.renderSymbol(*this, *layer.as<SymbolLayer>(), tileID, matrix);
+ const RenderTile& tile) {
+ painter.renderSymbol(parameters, *this, *layer.as<SymbolLayer>(), tile);
}
bool SymbolBucket::hasData() const { return hasTextData() || hasIconData() || !symbolInstances.empty(); }
@@ -119,9 +119,7 @@ void SymbolBucket::parseFeatures(const GeometryTileLayer& layer, const Filter& f
const GLsizei featureCount = static_cast<GLsizei>(layer.featureCount());
for (GLsizei i = 0; i < featureCount; i++) {
auto feature = layer.getFeature(i);
-
- FilterEvaluator evaluator(*feature);
- if (!Filter::visit(filter, evaluator))
+ if (!filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
continue;
SymbolFeature ft;
@@ -284,6 +282,8 @@ void SymbolBucket::addFeatures(uintptr_t tileUID,
}
if ((*image).relativePixelRatio != 1.0f) {
iconsNeedLinear = true;
+ } else if (layout.iconRotate != 0) {
+ iconsNeedLinear = true;
}
}
}
@@ -314,10 +314,10 @@ void SymbolBucket::addFeature(const GeometryCollection &lines,
const float iconPadding = layout.iconPadding * tilePixelRatio;
const float textMaxAngle = layout.textMaxAngle * util::DEG2RAD;
const bool textAlongLine =
- layout.textRotationAlignment == RotationAlignmentType::Map &&
+ layout.textRotationAlignment == AlignmentType::Map &&
layout.symbolPlacement == SymbolPlacementType::Line;
const bool iconAlongLine =
- layout.iconRotationAlignment == RotationAlignmentType::Map &&
+ layout.iconRotationAlignment == AlignmentType::Map &&
layout.symbolPlacement == SymbolPlacementType::Line;
const bool mayOverlap = layout.textAllowOverlap || layout.iconAllowOverlap ||
layout.textIgnorePlacement || layout.iconIgnorePlacement;
@@ -370,7 +370,7 @@ void SymbolBucket::addFeature(const GeometryCollection &lines,
}
}
}
-
+
bool SymbolBucket::anchorIsTooClose(const std::u32string &text, const float repeatDistance, Anchor &anchor) {
if (compareText.find(text) == compareText.end()) {
compareText.emplace(text, Anchors());
@@ -394,10 +394,10 @@ void SymbolBucket::placeFeatures(CollisionTile& collisionTile) {
// create the bufers used for rendering.
const bool textAlongLine =
- layout.textRotationAlignment == RotationAlignmentType::Map &&
+ layout.textRotationAlignment == AlignmentType::Map &&
layout.symbolPlacement == SymbolPlacementType::Line;
const bool iconAlongLine =
- layout.iconRotationAlignment == RotationAlignmentType::Map &&
+ layout.iconRotationAlignment == AlignmentType::Map &&
layout.symbolPlacement == SymbolPlacementType::Line;
const bool mayOverlap = layout.textAllowOverlap || layout.iconAllowOverlap ||
@@ -495,7 +495,7 @@ void SymbolBucket::addSymbols(Buffer &buffer, const SymbolQuads &symbols, float
const auto &anchorPoint = symbol.anchorPoint;
// drop upside down versions of glyphs
- const float a = std::fmod(symbol.angle + placementAngle + M_PI, M_PI * 2);
+ const float a = std::fmod(symbol.anchorAngle + placementAngle + M_PI, M_PI * 2);
if (keepUpright && alongLine && (a <= M_PI / 2 || a > M_PI * 3 / 2)) continue;
@@ -521,15 +521,18 @@ void SymbolBucket::addSymbols(Buffer &buffer, const SymbolQuads &symbols, float
auto &triangleGroup = *buffer.groups.back();
GLsizei triangleIndex = triangleGroup.vertex_length;
+ // Encode angle of glyph
+ uint8_t glyphAngle = std::round((symbol.glyphAngle / (M_PI * 2)) * 256);
+
// coordinates (2 triangles)
buffer.vertices.add(anchorPoint.x, anchorPoint.y, tl.x, tl.y, tex.x, tex.y, minZoom,
- maxZoom, placementZoom);
+ maxZoom, placementZoom, glyphAngle);
buffer.vertices.add(anchorPoint.x, anchorPoint.y, tr.x, tr.y, tex.x + tex.w, tex.y,
- minZoom, maxZoom, placementZoom);
+ minZoom, maxZoom, placementZoom, glyphAngle);
buffer.vertices.add(anchorPoint.x, anchorPoint.y, bl.x, bl.y, tex.x, tex.y + tex.h,
- minZoom, maxZoom, placementZoom);
+ minZoom, maxZoom, placementZoom, glyphAngle);
buffer.vertices.add(anchorPoint.x, anchorPoint.y, br.x, br.y, tex.x + tex.w, tex.y + tex.h,
- minZoom, maxZoom, placementZoom);
+ minZoom, maxZoom, placementZoom, glyphAngle);
// add the two triangles, referencing the four coordinates we just inserted.
buffer.triangles.add(triangleIndex + 0, triangleIndex + 1, triangleIndex + 2);
@@ -598,39 +601,39 @@ void SymbolBucket::swapRenderData() {
}
}
-void SymbolBucket::drawGlyphs(SDFShader& shader, gl::ObjectStore& store) {
+void SymbolBucket::drawGlyphs(SDFShader& shader, gl::ObjectStore& store, bool overdraw) {
GLbyte *vertex_index = BUFFER_OFFSET_0;
GLbyte *elements_index = BUFFER_OFFSET_0;
auto& text = renderData->text;
for (auto &group : text.groups) {
assert(group);
- group->array[0].bind(shader, text.vertices, text.triangles, vertex_index, store);
+ group->array[overdraw ? 1 : 0].bind(shader, text.vertices, text.triangles, vertex_index, store);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * text.vertices.itemSize;
elements_index += group->elements_length * text.triangles.itemSize;
}
}
-void SymbolBucket::drawIcons(SDFShader& shader, gl::ObjectStore& store) {
+void SymbolBucket::drawIcons(SDFShader& shader, gl::ObjectStore& store, bool overdraw) {
GLbyte *vertex_index = BUFFER_OFFSET_0;
GLbyte *elements_index = BUFFER_OFFSET_0;
auto& icon = renderData->icon;
for (auto &group : icon.groups) {
assert(group);
- group->array[0].bind(shader, icon.vertices, icon.triangles, vertex_index, store);
+ group->array[overdraw ? 1 : 0].bind(shader, icon.vertices, icon.triangles, vertex_index, store);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * icon.vertices.itemSize;
elements_index += group->elements_length * icon.triangles.itemSize;
}
}
-void SymbolBucket::drawIcons(IconShader& shader, gl::ObjectStore& store) {
+void SymbolBucket::drawIcons(IconShader& shader, gl::ObjectStore& store, bool overdraw) {
GLbyte *vertex_index = BUFFER_OFFSET_0;
GLbyte *elements_index = BUFFER_OFFSET_0;
auto& icon = renderData->icon;
for (auto &group : icon.groups) {
assert(group);
- group->array[1].bind(shader, icon.vertices, icon.triangles, vertex_index, store);
+ group->array[overdraw ? 3 : 2].bind(shader, icon.vertices, icon.triangles, vertex_index, store);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * icon.vertices.itemSize;
elements_index += group->elements_length * icon.triangles.itemSize;
diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp
index 314d44bdee..79c32e9d88 100644
--- a/src/mbgl/renderer/symbol_bucket.hpp
+++ b/src/mbgl/renderer/symbol_bucket.hpp
@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/geometry/vao.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
@@ -61,16 +61,16 @@ class SymbolInstance {
};
class SymbolBucket : public Bucket {
- typedef ElementGroup<1> TextElementGroup;
- typedef ElementGroup<2> IconElementGroup;
+ typedef ElementGroup<2> TextElementGroup;
+ typedef ElementGroup<4> IconElementGroup;
typedef ElementGroup<1> CollisionBoxElementGroup;
public:
- SymbolBucket(uint32_t overscaling, float zoom, const MapMode, const std::string& bucketName_, const std::string& sourceLayerName_);
+ SymbolBucket(uint32_t overscaling, float zoom, const MapMode, std::string bucketName_, std::string sourceLayerName_);
~SymbolBucket() override;
- void upload(gl::ObjectStore&) override;
- void render(Painter&, const style::Layer&, const UnwrappedTileID&, const mat4&) override;
+ void upload(gl::ObjectStore&, gl::Config&) override;
+ void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
bool hasData() const override;
bool hasTextData() const;
bool hasIconData() const;
@@ -82,9 +82,9 @@ public:
GlyphAtlas&,
GlyphStore&);
- void drawGlyphs(SDFShader&, gl::ObjectStore&);
- void drawIcons(SDFShader&, gl::ObjectStore&);
- void drawIcons(IconShader&, gl::ObjectStore&);
+ void drawGlyphs(SDFShader&, gl::ObjectStore&, bool overdraw);
+ void drawIcons(SDFShader&, gl::ObjectStore&, bool overdraw);
+ void drawIcons(IconShader&, gl::ObjectStore&, bool overdraw);
void drawCollisionBoxes(CollisionBoxShader&, gl::ObjectStore&);
void parseFeatures(const GeometryTileLayer&, const style::Filter&);
@@ -98,7 +98,7 @@ private:
const size_t index);
bool anchorIsTooClose(const std::u32string &text, const float repeatDistance, Anchor &anchor);
std::map<std::u32string, std::vector<Anchor>> compareText;
-
+
void addToDebugBuffers(CollisionTile &collisionTile);
void swapRenderData() override;
diff --git a/src/mbgl/shader/circle_shader.cpp b/src/mbgl/shader/circle_shader.cpp
index 2865769ee2..b19dbeba68 100644
--- a/src/mbgl/shader/circle_shader.cpp
+++ b/src/mbgl/shader/circle_shader.cpp
@@ -3,15 +3,18 @@
#include <mbgl/shader/circle.fragment.hpp>
#include <mbgl/gl/gl.hpp>
-#include <cstdio>
+namespace mbgl {
-using namespace mbgl;
-
-CircleShader::CircleShader(gl::ObjectStore& store)
- : Shader("circle", shaders::circle::vertex, shaders::circle::fragment, store) {
+CircleShader::CircleShader(gl::ObjectStore& store, Defines defines)
+ : Shader(shaders::circle::name,
+ shaders::circle::vertex,
+ shaders::circle::fragment,
+ store, defines) {
}
void CircleShader::bind(GLbyte* offset) {
MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_pos));
MBGL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 4, offset));
}
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/circle_shader.hpp b/src/mbgl/shader/circle_shader.hpp
index cd22d4c9b1..c454fc1337 100644
--- a/src/mbgl/shader/circle_shader.hpp
+++ b/src/mbgl/shader/circle_shader.hpp
@@ -2,22 +2,24 @@
#include <mbgl/shader/shader.hpp>
#include <mbgl/shader/uniform.hpp>
+#include <mbgl/util/color.hpp>
namespace mbgl {
class CircleShader : public Shader {
public:
- CircleShader(gl::ObjectStore&);
+ CircleShader(gl::ObjectStore&, Defines defines = None);
void bind(GLbyte *offset) final;
UniformMatrix<4> u_matrix = {"u_matrix", *this};
Uniform<std::array<GLfloat, 2>> u_extrude_scale = {"u_extrude_scale", *this};
Uniform<GLfloat> u_devicepixelratio = {"u_devicepixelratio", *this};
- Uniform<std::array<GLfloat, 4>> u_color = {"u_color", *this};
+ Uniform<Color> u_color = {"u_color", *this};
Uniform<GLfloat> u_radius = {"u_radius", *this};
Uniform<GLfloat> u_blur = {"u_blur", *this};
Uniform<GLfloat> u_opacity = {"u_opacity", *this};
+ Uniform<GLint> u_scale_with_map = {"u_scale_with_map", *this};
};
} // namespace mbgl
diff --git a/src/mbgl/shader/collision_box_shader.cpp b/src/mbgl/shader/collision_box_shader.cpp
index cf4ff81e96..bfee89fac2 100644
--- a/src/mbgl/shader/collision_box_shader.cpp
+++ b/src/mbgl/shader/collision_box_shader.cpp
@@ -3,14 +3,13 @@
#include <mbgl/shader/collisionbox.fragment.hpp>
#include <mbgl/gl/gl.hpp>
-#include <cstdio>
-
-using namespace mbgl;
+namespace mbgl {
CollisionBoxShader::CollisionBoxShader(gl::ObjectStore& store)
- : Shader("collisionbox", shaders::collisionbox::vertex, shaders::collisionbox::fragment, store)
- , a_extrude(MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_extrude")))
- , a_data(MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data"))) {
+ : Shader(shaders::collisionbox::name,
+ shaders::collisionbox::vertex,
+ shaders::collisionbox::fragment,
+ store) {
}
void CollisionBoxShader::bind(GLbyte *offset) {
@@ -24,5 +23,6 @@ void CollisionBoxShader::bind(GLbyte *offset) {
MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_data));
MBGL_CHECK_ERROR(glVertexAttribPointer(a_data, 2, GL_UNSIGNED_BYTE, false, stride, offset + 8));
-
}
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/collision_box_shader.hpp b/src/mbgl/shader/collision_box_shader.hpp
index a9b38a9849..bbd2611ce8 100644
--- a/src/mbgl/shader/collision_box_shader.hpp
+++ b/src/mbgl/shader/collision_box_shader.hpp
@@ -16,10 +16,6 @@ public:
Uniform<GLfloat> u_scale = {"u_scale", *this};
Uniform<GLfloat> u_zoom = {"u_zoom", *this};
Uniform<GLfloat> u_maxzoom = {"u_maxzoom", *this};
-
-protected:
- GLint a_extrude = -1;
- GLint a_data = -1;
};
} // namespace mbgl
diff --git a/src/mbgl/shader/icon_shader.cpp b/src/mbgl/shader/icon_shader.cpp
index 7fb0335dc8..d91fbe2ec0 100644
--- a/src/mbgl/shader/icon_shader.cpp
+++ b/src/mbgl/shader/icon_shader.cpp
@@ -3,15 +3,13 @@
#include <mbgl/shader/icon.fragment.hpp>
#include <mbgl/gl/gl.hpp>
-#include <cstdio>
+namespace mbgl {
-using namespace mbgl;
-
-IconShader::IconShader(gl::ObjectStore& store)
- : Shader("icon", shaders::icon::vertex, shaders::icon::fragment, store)
- , a_offset(MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_offset")))
- , a_data1(MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data1")))
- , a_data2(MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data2"))) {
+IconShader::IconShader(gl::ObjectStore& store, Defines defines)
+ : Shader(shaders::icon::name,
+ shaders::icon::vertex,
+ shaders::icon::fragment,
+ store, defines) {
}
void IconShader::bind(GLbyte* offset) {
@@ -29,3 +27,5 @@ void IconShader::bind(GLbyte* offset) {
MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_data2));
MBGL_CHECK_ERROR(glVertexAttribPointer(a_data2, 4, GL_UNSIGNED_BYTE, false, stride, offset + 12));
}
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/icon_shader.hpp b/src/mbgl/shader/icon_shader.hpp
index b8cfcabb10..86c7b8ece0 100644
--- a/src/mbgl/shader/icon_shader.hpp
+++ b/src/mbgl/shader/icon_shader.hpp
@@ -7,7 +7,7 @@ namespace mbgl {
class IconShader : public Shader {
public:
- IconShader(gl::ObjectStore&);
+ IconShader(gl::ObjectStore&, Defines defines = None);
void bind(GLbyte *offset) final;
@@ -16,14 +16,9 @@ public:
Uniform<GLfloat> u_zoom = {"u_zoom", *this};
Uniform<GLfloat> u_opacity = {"u_opacity", *this};
Uniform<std::array<GLfloat, 2>> u_texsize = {"u_texsize", *this};
- Uniform<GLint> u_skewed = {"u_skewed", *this};
+ Uniform<GLint> u_rotate_with_map = {"u_rotate_with_map", *this};
Uniform<GLint> u_texture = {"u_texture", *this};
Uniform<GLint> u_fadetexture = {"u_fadetexture", *this};
-
-protected:
- GLint a_offset = -1;
- GLint a_data1 = -1;
- GLint a_data2 = -1;
};
} // namespace mbgl
diff --git a/src/mbgl/shader/line_shader.cpp b/src/mbgl/shader/line_shader.cpp
index f21384082f..8c3ad32d73 100644
--- a/src/mbgl/shader/line_shader.cpp
+++ b/src/mbgl/shader/line_shader.cpp
@@ -3,13 +3,13 @@
#include <mbgl/shader/line.fragment.hpp>
#include <mbgl/gl/gl.hpp>
-#include <cstdio>
+namespace mbgl {
-using namespace mbgl;
-
-LineShader::LineShader(gl::ObjectStore& store)
- : Shader("line", shaders::line::vertex, shaders::line::fragment, store)
- , a_data(MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data"))) {
+LineShader::LineShader(gl::ObjectStore& store, Defines defines)
+ : Shader(shaders::line::name,
+ shaders::line::vertex,
+ shaders::line::fragment,
+ store, defines) {
}
void LineShader::bind(GLbyte* offset) {
@@ -19,3 +19,5 @@ void LineShader::bind(GLbyte* offset) {
MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_data));
MBGL_CHECK_ERROR(glVertexAttribPointer(a_data, 4, GL_UNSIGNED_BYTE, false, 8, offset + 4));
}
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/line_shader.hpp b/src/mbgl/shader/line_shader.hpp
index e0d14094a6..a2cda56314 100644
--- a/src/mbgl/shader/line_shader.hpp
+++ b/src/mbgl/shader/line_shader.hpp
@@ -2,17 +2,18 @@
#include <mbgl/shader/shader.hpp>
#include <mbgl/shader/uniform.hpp>
+#include <mbgl/util/color.hpp>
namespace mbgl {
class LineShader : public Shader {
public:
- LineShader(gl::ObjectStore&);
+ LineShader(gl::ObjectStore&, Defines defines = None);
void bind(GLbyte *offset) final;
UniformMatrix<4> u_matrix = {"u_matrix", *this};
- Uniform<std::array<GLfloat, 4>> u_color = {"u_color", *this};
+ Uniform<Color> u_color = {"u_color", *this};
Uniform<GLfloat> u_opacity = {"u_opacity", *this};
Uniform<GLfloat> u_ratio = {"u_ratio", *this};
Uniform<GLfloat> u_linewidth = {"u_linewidth", *this};
@@ -22,9 +23,6 @@ public:
Uniform<GLfloat> u_extra = {"u_extra", *this};
Uniform<GLfloat> u_offset = {"u_offset", *this};
UniformMatrix<2> u_antialiasingmatrix = {"u_antialiasingmatrix", *this};
-
-private:
- GLint a_data = -1;
};
diff --git a/src/mbgl/shader/linepattern_shader.cpp b/src/mbgl/shader/linepattern_shader.cpp
index a9923233af..48375dec24 100644
--- a/src/mbgl/shader/linepattern_shader.cpp
+++ b/src/mbgl/shader/linepattern_shader.cpp
@@ -3,13 +3,13 @@
#include <mbgl/shader/linepattern.fragment.hpp>
#include <mbgl/gl/gl.hpp>
-#include <cstdio>
+namespace mbgl {
-using namespace mbgl;
-
-LinepatternShader::LinepatternShader(gl::ObjectStore& store)
- : Shader("linepattern", shaders::linepattern::vertex, shaders::linepattern::fragment, store)
- , a_data(MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data"))) {
+LinepatternShader::LinepatternShader(gl::ObjectStore& store, Defines defines)
+ : Shader(shaders::linepattern::name,
+ shaders::linepattern::vertex,
+ shaders::linepattern::fragment,
+ store, defines) {
}
void LinepatternShader::bind(GLbyte* offset) {
@@ -19,3 +19,5 @@ void LinepatternShader::bind(GLbyte* offset) {
MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_data));
MBGL_CHECK_ERROR(glVertexAttribPointer(a_data, 4, GL_UNSIGNED_BYTE, false, 8, offset + 4));
}
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/linepattern_shader.hpp b/src/mbgl/shader/linepattern_shader.hpp
index c34c1a5292..6c44716d10 100644
--- a/src/mbgl/shader/linepattern_shader.hpp
+++ b/src/mbgl/shader/linepattern_shader.hpp
@@ -7,7 +7,7 @@ namespace mbgl {
class LinepatternShader : public Shader {
public:
- LinepatternShader(gl::ObjectStore&);
+ LinepatternShader(gl::ObjectStore&, Defines defines = None);
void bind(GLbyte *offset) final;
@@ -30,8 +30,6 @@ public:
Uniform<GLfloat> u_offset = {"u_offset", *this};
Uniform<GLint> u_image = {"u_image", *this};
UniformMatrix<2> u_antialiasingmatrix = {"u_antialiasingmatrix", *this};
-
-private:
- GLint a_data = -1;
};
+
} // namespace mbgl
diff --git a/src/mbgl/shader/linesdf_shader.cpp b/src/mbgl/shader/linesdf_shader.cpp
index b316d2562d..8b2e983e0d 100644
--- a/src/mbgl/shader/linesdf_shader.cpp
+++ b/src/mbgl/shader/linesdf_shader.cpp
@@ -3,13 +3,13 @@
#include <mbgl/shader/linesdfpattern.fragment.hpp>
#include <mbgl/gl/gl.hpp>
-#include <cstdio>
+namespace mbgl {
-using namespace mbgl;
-
-LineSDFShader::LineSDFShader(gl::ObjectStore& store)
- : Shader("linesdfpattern", shaders::linesdfpattern::vertex, shaders::linesdfpattern::fragment, store)
- , a_data(MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data"))) {
+LineSDFShader::LineSDFShader(gl::ObjectStore& store, Defines defines)
+ : Shader(shaders::linesdfpattern::name,
+ shaders::linesdfpattern::vertex,
+ shaders::linesdfpattern::fragment,
+ store, defines) {
}
void LineSDFShader::bind(GLbyte* offset) {
@@ -19,3 +19,5 @@ void LineSDFShader::bind(GLbyte* offset) {
MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_data));
MBGL_CHECK_ERROR(glVertexAttribPointer(a_data, 4, GL_UNSIGNED_BYTE, false, 8, offset + 4));
}
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/linesdf_shader.hpp b/src/mbgl/shader/linesdf_shader.hpp
index 8791f243c0..ce1fe4d17c 100644
--- a/src/mbgl/shader/linesdf_shader.hpp
+++ b/src/mbgl/shader/linesdf_shader.hpp
@@ -2,17 +2,18 @@
#include <mbgl/shader/shader.hpp>
#include <mbgl/shader/uniform.hpp>
+#include <mbgl/util/color.hpp>
namespace mbgl {
class LineSDFShader : public Shader {
public:
- LineSDFShader(gl::ObjectStore&);
+ LineSDFShader(gl::ObjectStore&, Defines defines = None);
void bind(GLbyte *offset) final;
UniformMatrix<4> u_matrix = {"u_matrix", *this};
- Uniform<std::array<GLfloat, 4>> u_color = {"u_color", *this};
+ Uniform<Color> u_color = {"u_color", *this};
Uniform<GLfloat> u_opacity = {"u_opacity", *this};
Uniform<GLfloat> u_linewidth = {"u_linewidth", *this};
Uniform<GLfloat> u_gapwidth = {"u_gapwidth", *this};
@@ -29,9 +30,6 @@ public:
Uniform<GLfloat> u_extra = {"u_extra", *this};
Uniform<GLfloat> u_offset = {"u_offset", *this};
UniformMatrix<2> u_antialiasingmatrix = {"u_antialiasingmatrix", *this};
-
-private:
- GLint a_data = -1;
};
diff --git a/src/mbgl/shader/outline_shader.cpp b/src/mbgl/shader/outline_shader.cpp
index 58a647f375..58f73d9f44 100644
--- a/src/mbgl/shader/outline_shader.cpp
+++ b/src/mbgl/shader/outline_shader.cpp
@@ -3,15 +3,18 @@
#include <mbgl/shader/outline.fragment.hpp>
#include <mbgl/gl/gl.hpp>
-#include <cstdio>
+namespace mbgl {
-using namespace mbgl;
-
-OutlineShader::OutlineShader(gl::ObjectStore& store)
- : Shader("outline", shaders::outline::vertex, shaders::outline::fragment, store) {
+OutlineShader::OutlineShader(gl::ObjectStore& store, Defines defines)
+ : Shader(shaders::outline::name,
+ shaders::outline::vertex,
+ shaders::outline::fragment,
+ store, defines) {
}
void OutlineShader::bind(GLbyte* offset) {
MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_pos));
MBGL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset));
}
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/outline_shader.hpp b/src/mbgl/shader/outline_shader.hpp
index 25c873b4fe..5840ad2238 100644
--- a/src/mbgl/shader/outline_shader.hpp
+++ b/src/mbgl/shader/outline_shader.hpp
@@ -2,17 +2,18 @@
#include <mbgl/shader/shader.hpp>
#include <mbgl/shader/uniform.hpp>
+#include <mbgl/util/color.hpp>
namespace mbgl {
class OutlineShader : public Shader {
public:
- OutlineShader(gl::ObjectStore&);
+ OutlineShader(gl::ObjectStore&, Defines defines = None);
void bind(GLbyte *offset) final;
UniformMatrix<4> u_matrix = {"u_matrix", *this};
- Uniform<std::array<GLfloat, 4>> u_outline_color = {"u_outline_color", *this};
+ Uniform<Color> u_outline_color = {"u_outline_color", *this};
Uniform<GLfloat> u_opacity = {"u_opacity", *this};
Uniform<std::array<GLfloat, 2>> u_world = {"u_world", *this};
};
diff --git a/src/mbgl/shader/outlinepattern_shader.cpp b/src/mbgl/shader/outlinepattern_shader.cpp
index 5ffa458a4f..2373a75370 100644
--- a/src/mbgl/shader/outlinepattern_shader.cpp
+++ b/src/mbgl/shader/outlinepattern_shader.cpp
@@ -3,19 +3,18 @@
#include <mbgl/shader/outlinepattern.fragment.hpp>
#include <mbgl/gl/gl.hpp>
-#include <cstdio>
+namespace mbgl {
-using namespace mbgl;
-
-OutlinePatternShader::OutlinePatternShader(gl::ObjectStore& store)
- : Shader(
- "outlinepattern",
- shaders::outlinepattern::vertex, shaders::outlinepattern::fragment,
- store
- ) {
+OutlinePatternShader::OutlinePatternShader(gl::ObjectStore& store, Defines defines)
+ : Shader(shaders::outlinepattern::name,
+ shaders::outlinepattern::vertex,
+ shaders::outlinepattern::fragment,
+ store, defines) {
}
void OutlinePatternShader::bind(GLbyte *offset) {
MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_pos));
MBGL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset));
}
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/outlinepattern_shader.hpp b/src/mbgl/shader/outlinepattern_shader.hpp
index e124923b6f..6869763412 100644
--- a/src/mbgl/shader/outlinepattern_shader.hpp
+++ b/src/mbgl/shader/outlinepattern_shader.hpp
@@ -7,23 +7,26 @@ namespace mbgl {
class OutlinePatternShader : public Shader {
public:
- OutlinePatternShader(gl::ObjectStore&);
+ OutlinePatternShader(gl::ObjectStore&, Defines defines = None);
void bind(GLbyte *offset) final;
- UniformMatrix<4> u_matrix = {"u_matrix", *this};
- Uniform<std::array<GLfloat, 2>> u_pattern_tl_a = {"u_pattern_tl_a", *this};
- Uniform<std::array<GLfloat, 2>> u_pattern_br_a = {"u_pattern_br_a", *this};
- Uniform<std::array<GLfloat, 2>> u_pattern_tl_b = {"u_pattern_tl_b", *this};
- Uniform<std::array<GLfloat, 2>> u_pattern_br_b = {"u_pattern_br_b", *this};
- Uniform<GLfloat> u_opacity = {"u_opacity", *this};
- Uniform<GLfloat> u_mix = {"u_mix", *this};
- Uniform<GLint> u_image = {"u_image", *this};
- Uniform<std::array<GLfloat, 2>> u_patternscale_a = {"u_patternscale_a", *this};
- Uniform<std::array<GLfloat, 2>> u_patternscale_b = {"u_patternscale_b", *this};
- Uniform<std::array<GLfloat, 2>> u_offset_a = {"u_offset_a", *this};
- Uniform<std::array<GLfloat, 2>> u_offset_b = {"u_offset_b", *this};
- Uniform<std::array<GLfloat, 2>> u_world = {"u_world", *this};
+ UniformMatrix<4> u_matrix = {"u_matrix", *this};
+ Uniform<std::array<GLfloat, 2>> u_pattern_tl_a = {"u_pattern_tl_a", *this};
+ Uniform<std::array<GLfloat, 2>> u_pattern_br_a = {"u_pattern_br_a", *this};
+ Uniform<std::array<GLfloat, 2>> u_pattern_tl_b = {"u_pattern_tl_b", *this};
+ Uniform<std::array<GLfloat, 2>> u_pattern_br_b = {"u_pattern_br_b", *this};
+ Uniform<GLfloat> u_opacity = {"u_opacity", *this};
+ Uniform<GLfloat> u_mix = {"u_mix", *this};
+ Uniform<GLfloat> u_scale_a = {"u_scale_a", *this};
+ Uniform<GLfloat> u_scale_b = {"u_scale_b", *this};
+ Uniform<GLfloat> u_tile_units_to_pixels = {"u_tile_units_to_pixels", *this};
+ Uniform<GLint> u_image = {"u_image", *this};
+ Uniform<std::array<GLfloat, 2>> u_pattern_size_a = {"u_pattern_size_a", *this};
+ Uniform<std::array<GLfloat, 2>> u_pattern_size_b = {"u_pattern_size_b", *this};
+ Uniform<std::array<GLfloat, 2>> u_pixel_coord_upper = {"u_pixel_coord_upper", *this};
+ Uniform<std::array<GLfloat, 2>> u_pixel_coord_lower = {"u_pixel_coord_lower", *this};
+ Uniform<std::array<GLfloat, 2>> u_world = {"u_world", *this};
};
} // namespace mbgl
diff --git a/src/mbgl/shader/pattern_shader.cpp b/src/mbgl/shader/pattern_shader.cpp
index 64a72d1451..5caa892feb 100644
--- a/src/mbgl/shader/pattern_shader.cpp
+++ b/src/mbgl/shader/pattern_shader.cpp
@@ -3,19 +3,18 @@
#include <mbgl/shader/pattern.fragment.hpp>
#include <mbgl/gl/gl.hpp>
-#include <cstdio>
+namespace mbgl {
-using namespace mbgl;
-
-PatternShader::PatternShader(gl::ObjectStore& store)
- : Shader(
- "pattern",
- shaders::pattern::vertex, shaders::pattern::fragment,
- store
- ) {
+PatternShader::PatternShader(gl::ObjectStore& store, Defines defines)
+ : Shader(shaders::pattern::name,
+ shaders::pattern::vertex,
+ shaders::pattern::fragment,
+ store, defines) {
}
void PatternShader::bind(GLbyte *offset) {
MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_pos));
MBGL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset));
}
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/pattern_shader.hpp b/src/mbgl/shader/pattern_shader.hpp
index ae515c1948..ae356fdfb7 100644
--- a/src/mbgl/shader/pattern_shader.hpp
+++ b/src/mbgl/shader/pattern_shader.hpp
@@ -7,22 +7,25 @@ namespace mbgl {
class PatternShader : public Shader {
public:
- PatternShader(gl::ObjectStore&);
+ PatternShader(gl::ObjectStore&, Defines defines = None);
void bind(GLbyte *offset) final;
- UniformMatrix<4> u_matrix = {"u_matrix", *this};
- Uniform<std::array<GLfloat, 2>> u_pattern_tl_a = {"u_pattern_tl_a", *this};
- Uniform<std::array<GLfloat, 2>> u_pattern_br_a = {"u_pattern_br_a", *this};
- Uniform<std::array<GLfloat, 2>> u_pattern_tl_b = {"u_pattern_tl_b", *this};
- Uniform<std::array<GLfloat, 2>> u_pattern_br_b = {"u_pattern_br_b", *this};
- Uniform<GLfloat> u_opacity = {"u_opacity", *this};
- Uniform<GLfloat> u_mix = {"u_mix", *this};
- Uniform<GLint> u_image = {"u_image", *this};
- Uniform<std::array<GLfloat, 2>> u_patternscale_a = {"u_patternscale_a", *this};
- Uniform<std::array<GLfloat, 2>> u_patternscale_b = {"u_patternscale_b", *this};
- Uniform<std::array<GLfloat, 2>> u_offset_a = {"u_offset_a", *this};
- Uniform<std::array<GLfloat, 2>> u_offset_b = {"u_offset_b", *this};
+ UniformMatrix<4> u_matrix = {"u_matrix", *this};
+ Uniform<std::array<GLfloat, 2>> u_pattern_tl_a = {"u_pattern_tl_a", *this};
+ Uniform<std::array<GLfloat, 2>> u_pattern_br_a = {"u_pattern_br_a", *this};
+ Uniform<std::array<GLfloat, 2>> u_pattern_tl_b = {"u_pattern_tl_b", *this};
+ Uniform<std::array<GLfloat, 2>> u_pattern_br_b = {"u_pattern_br_b", *this};
+ Uniform<GLfloat> u_opacity = {"u_opacity", *this};
+ Uniform<GLfloat> u_mix = {"u_mix", *this};
+ Uniform<GLfloat> u_scale_a = {"u_scale_a", *this};
+ Uniform<GLfloat> u_scale_b = {"u_scale_b", *this};
+ Uniform<GLfloat> u_tile_units_to_pixels = {"u_tile_units_to_pixels", *this};
+ Uniform<GLint> u_image = {"u_image", *this};
+ Uniform<std::array<GLfloat, 2>> u_pattern_size_a = {"u_pattern_size_a", *this};
+ Uniform<std::array<GLfloat, 2>> u_pattern_size_b = {"u_pattern_size_b", *this};
+ Uniform<std::array<GLfloat, 2>> u_pixel_coord_upper = {"u_pixel_coord_upper", *this};
+ Uniform<std::array<GLfloat, 2>> u_pixel_coord_lower = {"u_pixel_coord_lower", *this};
};
} // namespace mbgl
diff --git a/src/mbgl/shader/plain_shader.cpp b/src/mbgl/shader/plain_shader.cpp
index c030a2d7b3..1309c4f14a 100644
--- a/src/mbgl/shader/plain_shader.cpp
+++ b/src/mbgl/shader/plain_shader.cpp
@@ -3,15 +3,18 @@
#include <mbgl/shader/fill.fragment.hpp>
#include <mbgl/gl/gl.hpp>
-#include <cstdio>
+namespace mbgl {
-using namespace mbgl;
-
-PlainShader::PlainShader(gl::ObjectStore& store)
- : Shader("fill", shaders::fill::vertex, shaders::fill::fragment, store) {
+PlainShader::PlainShader(gl::ObjectStore& store, Defines defines)
+ : Shader(shaders::fill::name,
+ shaders::fill::vertex,
+ shaders::fill::fragment,
+ store, defines) {
}
void PlainShader::bind(GLbyte* offset) {
MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_pos));
MBGL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset));
}
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/plain_shader.hpp b/src/mbgl/shader/plain_shader.hpp
index 7edf4b4b19..a126fa30a9 100644
--- a/src/mbgl/shader/plain_shader.hpp
+++ b/src/mbgl/shader/plain_shader.hpp
@@ -2,17 +2,18 @@
#include <mbgl/shader/shader.hpp>
#include <mbgl/shader/uniform.hpp>
+#include <mbgl/util/color.hpp>
namespace mbgl {
class PlainShader : public Shader {
public:
- PlainShader(gl::ObjectStore&);
+ PlainShader(gl::ObjectStore&, Defines defines = None);
void bind(GLbyte *offset) final;
UniformMatrix<4> u_matrix = {"u_matrix", *this};
- Uniform<std::array<GLfloat, 4>> u_color = {"u_color", *this};
+ Uniform<Color> u_color = {"u_color", *this};
Uniform<GLfloat> u_opacity = {"u_opacity", *this};
};
diff --git a/src/mbgl/shader/raster_shader.cpp b/src/mbgl/shader/raster_shader.cpp
index e5e290bedd..76723b06e9 100644
--- a/src/mbgl/shader/raster_shader.cpp
+++ b/src/mbgl/shader/raster_shader.cpp
@@ -3,15 +3,23 @@
#include <mbgl/shader/raster.fragment.hpp>
#include <mbgl/gl/gl.hpp>
-#include <cstdio>
+namespace mbgl {
-using namespace mbgl;
-
-RasterShader::RasterShader(gl::ObjectStore& store)
- : Shader("raster", shaders::raster::vertex, shaders::raster::fragment, store) {
+RasterShader::RasterShader(gl::ObjectStore& store, Defines defines)
+ : Shader(shaders::raster::name,
+ shaders::raster::vertex,
+ shaders::raster::fragment,
+ store, defines) {
}
void RasterShader::bind(GLbyte* offset) {
+ const GLint stride = 8;
+
MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_pos));
- MBGL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset));
+ MBGL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_SHORT, false, stride, offset));
+
+ MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_texture_pos));
+ MBGL_CHECK_ERROR(glVertexAttribPointer(a_texture_pos, 2, GL_SHORT, false, stride, offset + 4));
}
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/raster_shader.hpp b/src/mbgl/shader/raster_shader.hpp
index ee53385a0b..4b3ba9168b 100644
--- a/src/mbgl/shader/raster_shader.hpp
+++ b/src/mbgl/shader/raster_shader.hpp
@@ -7,19 +7,23 @@ namespace mbgl {
class RasterShader : public Shader {
public:
- RasterShader(gl::ObjectStore&);
+ RasterShader(gl::ObjectStore&, Defines defines = None);
void bind(GLbyte *offset) final;
UniformMatrix<4> u_matrix = {"u_matrix", *this};
- Uniform<GLint> u_image = {"u_image", *this};
- Uniform<GLfloat> u_opacity = {"u_opacity", *this};
- Uniform<GLfloat> u_buffer = {"u_buffer", *this};
+ Uniform<GLint> u_image0 = {"u_image0", *this};
+ Uniform<GLint> u_image1 = {"u_image1", *this};
+ Uniform<GLfloat> u_opacity0 = {"u_opacity0", *this};
+ Uniform<GLfloat> u_opacity1 = {"u_opacity1", *this};
+ Uniform<GLfloat> u_buffer_scale = {"u_buffer_scale", *this};
Uniform<GLfloat> u_brightness_low = {"u_brightness_low", *this};
Uniform<GLfloat> u_brightness_high = {"u_brightness_high", *this};
Uniform<GLfloat> u_saturation_factor = {"u_saturation_factor", *this};
Uniform<GLfloat> u_contrast_factor = {"u_contrast_factor", *this};
Uniform<std::array<GLfloat, 3>> u_spin_weights = {"u_spin_weights", *this};
+ Uniform<std::array<GLfloat, 2>> u_tl_parent = {"u_tl_parent", *this};
+ Uniform<GLfloat> u_scale_parent = {"u_scale_parent", *this};
};
} // namespace mbgl
diff --git a/src/mbgl/shader/sdf_shader.cpp b/src/mbgl/shader/sdf_shader.cpp
index 76ea1e3b4d..24b6f77d68 100644
--- a/src/mbgl/shader/sdf_shader.cpp
+++ b/src/mbgl/shader/sdf_shader.cpp
@@ -3,18 +3,16 @@
#include <mbgl/shader/sdf.fragment.hpp>
#include <mbgl/gl/gl.hpp>
-#include <cstdio>
+namespace mbgl {
-using namespace mbgl;
-
-SDFShader::SDFShader(gl::ObjectStore& store)
- : Shader("sdf", shaders::sdf::vertex, shaders::sdf::fragment, store)
- , a_offset(MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_offset")))
- , a_data1(MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data1")))
- , a_data2(MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data2"))) {
+SDFShader::SDFShader(gl::ObjectStore& store, Defines defines)
+ : Shader(shaders::sdf::name,
+ shaders::sdf::vertex,
+ shaders::sdf::fragment,
+ store, defines) {
}
-void SDFGlyphShader::bind(GLbyte* offset) {
+void SDFShader::bind(GLbyte* offset) {
const int stride = 16;
MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_pos));
@@ -30,18 +28,4 @@ void SDFGlyphShader::bind(GLbyte* offset) {
MBGL_CHECK_ERROR(glVertexAttribPointer(a_data2, 4, GL_UNSIGNED_BYTE, false, stride, offset + 12));
}
-void SDFIconShader::bind(GLbyte* offset) {
- const int stride = 16;
-
- MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_pos));
- MBGL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_SHORT, false, stride, offset + 0));
-
- MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_offset));
- MBGL_CHECK_ERROR(glVertexAttribPointer(a_offset, 2, GL_SHORT, false, stride, offset + 4));
-
- MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_data1));
- MBGL_CHECK_ERROR(glVertexAttribPointer(a_data1, 4, GL_UNSIGNED_BYTE, false, stride, offset + 8));
-
- MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_data2));
- MBGL_CHECK_ERROR(glVertexAttribPointer(a_data2, 4, GL_UNSIGNED_BYTE, false, stride, offset + 12));
-}
+} // namespace mbgl
diff --git a/src/mbgl/shader/sdf_shader.hpp b/src/mbgl/shader/sdf_shader.hpp
index f067c30aeb..f2f79f1cc9 100644
--- a/src/mbgl/shader/sdf_shader.hpp
+++ b/src/mbgl/shader/sdf_shader.hpp
@@ -2,40 +2,30 @@
#include <mbgl/shader/shader.hpp>
#include <mbgl/shader/uniform.hpp>
+#include <mbgl/util/color.hpp>
namespace mbgl {
class SDFShader : public Shader {
public:
- SDFShader(gl::ObjectStore&);
+ SDFShader(gl::ObjectStore&, Defines defines = None);
UniformMatrix<4> u_matrix = {"u_matrix", *this};
Uniform<std::array<GLfloat, 2>> u_extrude_scale = {"u_extrude_scale", *this};
- Uniform<std::array<GLfloat, 4>> u_color = {"u_color", *this};
+ Uniform<Color> u_color = {"u_color", *this};
Uniform<GLfloat> u_opacity = {"u_opacity", *this};
Uniform<std::array<GLfloat, 2>> u_texsize = {"u_texsize", *this};
Uniform<GLfloat> u_buffer = {"u_buffer", *this};
Uniform<GLfloat> u_gamma = {"u_gamma", *this};
Uniform<GLfloat> u_zoom = {"u_zoom", *this};
- Uniform<GLint> u_skewed = {"u_skewed", *this};
+ Uniform<GLfloat> u_pitch = {"u_pitch", *this};
+ Uniform<GLfloat> u_bearing = {"u_bearing", *this};
+ Uniform<GLfloat> u_aspect_ratio = {"u_aspect_ratio", *this};
+ Uniform<GLint> u_rotate_with_map = {"u_rotate_with_map",*this};
+ Uniform<GLint> u_pitch_with_map = {"u_pitch_with_map",*this};
Uniform<GLint> u_texture = {"u_texture", *this};
Uniform<GLint> u_fadetexture = {"u_fadetexture", *this};
-protected:
- GLint a_offset = -1;
- GLint a_data1 = -1;
- GLint a_data2 = -1;
-};
-
-class SDFGlyphShader : public SDFShader {
-public:
- SDFGlyphShader(gl::ObjectStore& store) : SDFShader(store) {}
- void bind(GLbyte *offset) final;
-};
-
-class SDFIconShader : public SDFShader {
-public:
- SDFIconShader(gl::ObjectStore& store) : SDFShader(store) {}
void bind(GLbyte *offset) final;
};
diff --git a/src/mbgl/shader/shader.cpp b/src/mbgl/shader/shader.cpp
index 23ea043720..ae36d21740 100644
--- a/src/mbgl/shader/shader.cpp
+++ b/src/mbgl/shader/shader.cpp
@@ -8,12 +8,14 @@
#include <cstring>
#include <cassert>
#include <iostream>
+#include <string>
#include <fstream>
#include <cstdio>
+#include <cassert>
namespace mbgl {
-Shader::Shader(const char *name_, const GLchar *vertSource, const GLchar *fragSource, gl::ObjectStore& store)
+Shader::Shader(const char* name_, const char* vertexSource, const char* fragmentSource, gl::ObjectStore& store, Defines defines)
: name(name_)
, program(store.createProgram())
, vertexShader(store.createShader(GL_VERTEX_SHADER))
@@ -21,13 +23,19 @@ Shader::Shader(const char *name_, const GLchar *vertSource, const GLchar *fragSo
{
util::stopwatch stopwatch("shader compilation", Event::Shader);
- if (!compileShader(vertexShader, &vertSource)) {
- Log::Error(Event::Shader, "Vertex shader %s failed to compile: %s", name, vertSource);
+ if (!compileShader(vertexShader, vertexSource)) {
+ Log::Error(Event::Shader, "Vertex shader %s failed to compile: %s", name, vertexSource);
throw util::ShaderException(std::string { "Vertex shader " } + name + " failed to compile");
}
- if (!compileShader(fragmentShader, &fragSource)) {
- Log::Error(Event::Shader, "Fragment shader %s failed to compile: %s", name, fragSource);
+ std::string fragment(fragmentSource);
+ if (defines & Defines::Overdraw) {
+ assert(fragment.find("#ifdef OVERDRAW_INSPECTOR") != std::string::npos);
+ fragment.replace(fragment.find_first_of('\n'), 1, "\n#define OVERDRAW_INSPECTOR\n");
+ }
+
+ if (!compileShader(fragmentShader, fragment.c_str())) {
+ Log::Error(Event::Shader, "Fragment shader %s failed to compile: %s", name, fragmentSource);
throw util::ShaderException(std::string { "Fragment shader " } + name + " failed to compile");
}
@@ -35,32 +43,37 @@ Shader::Shader(const char *name_, const GLchar *vertSource, const GLchar *fragSo
MBGL_CHECK_ERROR(glAttachShader(program.get(), vertexShader.get()));
MBGL_CHECK_ERROR(glAttachShader(program.get(), fragmentShader.get()));
- {
- // Link program
- GLint status;
- MBGL_CHECK_ERROR(glLinkProgram(program.get()));
+ // Bind attribute variables
+ MBGL_CHECK_ERROR(glBindAttribLocation(program.get(), a_pos, "a_pos"));
+ MBGL_CHECK_ERROR(glBindAttribLocation(program.get(), a_extrude, "a_extrude"));
+ MBGL_CHECK_ERROR(glBindAttribLocation(program.get(), a_offset, "a_offset"));
+ MBGL_CHECK_ERROR(glBindAttribLocation(program.get(), a_data, "a_data"));
+ MBGL_CHECK_ERROR(glBindAttribLocation(program.get(), a_data1, "a_data1"));
+ MBGL_CHECK_ERROR(glBindAttribLocation(program.get(), a_data2, "a_data2"));
+ MBGL_CHECK_ERROR(glBindAttribLocation(program.get(), a_texture_pos, "a_texture_pos"));
- MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_LINK_STATUS, &status));
- if (status == 0) {
- GLint logLength;
- MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_INFO_LOG_LENGTH, &logLength));
- const auto log = std::make_unique<GLchar[]>(logLength);
- if (logLength > 0) {
- MBGL_CHECK_ERROR(glGetProgramInfoLog(program.get(), logLength, &logLength, log.get()));
- Log::Error(Event::Shader, "Program failed to link: %s", log.get());
- }
- throw util::ShaderException(std::string { "Program " } + name + " failed to link: " + log.get());
+ // Link program
+ GLint status;
+ MBGL_CHECK_ERROR(glLinkProgram(program.get()));
+
+ MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_LINK_STATUS, &status));
+ if (status == 0) {
+ GLint logLength;
+ MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_INFO_LOG_LENGTH, &logLength));
+ const auto log = std::make_unique<GLchar[]>(logLength);
+ if (logLength > 0) {
+ MBGL_CHECK_ERROR(glGetProgramInfoLog(program.get(), logLength, &logLength, log.get()));
+ Log::Error(Event::Shader, "Program failed to link: %s", log.get());
}
+ throw util::ShaderException(std::string { "Program " } + name + " failed to link: " + log.get());
}
-
- a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program.get(), "a_pos"));
}
-bool Shader::compileShader(gl::UniqueShader& shader, const GLchar *source[]) {
+bool Shader::compileShader(gl::UniqueShader& shader, const GLchar *source) {
GLint status = 0;
- const GLsizei lengths = static_cast<GLsizei>(std::strlen(*source));
- MBGL_CHECK_ERROR(glShaderSource(shader.get(), 1, source, &lengths));
+ const GLsizei lengths = static_cast<GLsizei>(std::strlen(source));
+ MBGL_CHECK_ERROR(glShaderSource(shader.get(), 1, &source, &lengths));
MBGL_CHECK_ERROR(glCompileShader(shader.get()));
diff --git a/src/mbgl/shader/shader.hpp b/src/mbgl/shader/shader.hpp
index 1cb2a5601f..f7da0c91ab 100644
--- a/src/mbgl/shader/shader.hpp
+++ b/src/mbgl/shader/shader.hpp
@@ -3,15 +3,14 @@
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/object_store.hpp>
#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/optional.hpp>
namespace mbgl {
class Shader : private util::noncopyable {
public:
- Shader(const GLchar *name, const GLchar *vertex, const GLchar *fragment, gl::ObjectStore&);
-
~Shader();
- const GLchar *name;
+ const char* name;
GLuint getID() const {
return program.get();
@@ -19,11 +18,28 @@ public:
virtual void bind(GLbyte *offset) = 0;
+ enum Defines : bool {
+ None = false,
+ Overdraw = true,
+ };
+
protected:
- GLint a_pos = -1;
+ Shader(const char* name_,
+ const char* vertex,
+ const char* fragment,
+ gl::ObjectStore&,
+ Defines defines = Defines::None);
+
+ static constexpr GLint a_pos = 0;
+ static constexpr GLint a_extrude = 1;
+ static constexpr GLint a_offset = 2;
+ static constexpr GLint a_data = 3;
+ static constexpr GLint a_data1 = 4;
+ static constexpr GLint a_data2 = 5;
+ static constexpr GLint a_texture_pos = 6;
private:
- bool compileShader(gl::UniqueShader&, const GLchar *source[]);
+ bool compileShader(gl::UniqueShader&, const GLchar *source);
gl::UniqueProgram program;
gl::UniqueShader vertexShader;
diff --git a/src/mbgl/shader/shaders.hpp b/src/mbgl/shader/shaders.hpp
new file mode 100644
index 0000000000..088e351d37
--- /dev/null
+++ b/src/mbgl/shader/shaders.hpp
@@ -0,0 +1,59 @@
+#pragma once
+
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/object_store.hpp>
+
+#include <mbgl/shader/pattern_shader.hpp>
+#include <mbgl/shader/plain_shader.hpp>
+#include <mbgl/shader/outline_shader.hpp>
+#include <mbgl/shader/outlinepattern_shader.hpp>
+#include <mbgl/shader/line_shader.hpp>
+#include <mbgl/shader/linesdf_shader.hpp>
+#include <mbgl/shader/linepattern_shader.hpp>
+#include <mbgl/shader/icon_shader.hpp>
+#include <mbgl/shader/raster_shader.hpp>
+#include <mbgl/shader/sdf_shader.hpp>
+#include <mbgl/shader/collision_box_shader.hpp>
+#include <mbgl/shader/circle_shader.hpp>
+
+namespace mbgl {
+
+class Shaders {
+public:
+ Shaders(gl::ObjectStore& store, Shader::Defines defines = Shader::None)
+ : plain(store, defines),
+ outline(store, defines),
+ outlinePattern(store, defines),
+ line(store, defines),
+ linesdf(store, defines),
+ linepattern(store, defines),
+ pattern(store, defines),
+ icon(store, defines),
+ raster(store, defines),
+ sdfGlyph(store, defines),
+ sdfIcon(store, defines),
+ collisionBox(store),
+ circle(store, defines)
+ {}
+
+ PlainShader plain;
+ OutlineShader outline;
+ OutlinePatternShader outlinePattern;
+ LineShader line;
+ LineSDFShader linesdf;
+ LinepatternShader linepattern;
+ PatternShader pattern;
+ IconShader icon;
+ RasterShader raster;
+ SDFShader sdfGlyph;
+ SDFShader sdfIcon;
+ CollisionBoxShader collisionBox;
+ CircleShader circle;
+
+ VertexArrayObject coveringPlainArray;
+ VertexArrayObject coveringRasterArray;
+ VertexArrayObject backgroundPatternArray;
+ VertexArrayObject backgroundArray;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/uniform.cpp b/src/mbgl/shader/uniform.cpp
index d43dd20016..4c7646119a 100644
--- a/src/mbgl/shader/uniform.cpp
+++ b/src/mbgl/shader/uniform.cpp
@@ -1,4 +1,5 @@
#include <mbgl/shader/uniform.hpp>
+#include <mbgl/util/color.hpp>
namespace mbgl {
@@ -28,6 +29,12 @@ void Uniform<std::array<GLfloat, 4>>::bind(const std::array<GLfloat, 4>& t) {
}
template <>
+void Uniform<Color>::bind(const Color& t) {
+ std::array<GLfloat, 4> a = {{ t.r, t.g, t.b, t.a }};
+ MBGL_CHECK_ERROR(glUniform4fv(location, 1, a.data()));
+}
+
+template <>
void UniformMatrix<2>::bind(const std::array<GLfloat, 4>& t) {
MBGL_CHECK_ERROR(glUniformMatrix2fv(location, 1, GL_FALSE, t.data()));
}
diff --git a/src/mbgl/sprite/sprite_atlas.cpp b/src/mbgl/sprite/sprite_atlas.cpp
index 5d7d01deb3..05b713f454 100644
--- a/src/mbgl/sprite/sprite_atlas.cpp
+++ b/src/mbgl/sprite/sprite_atlas.cpp
@@ -1,6 +1,7 @@
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/sprite/sprite_store.hpp>
#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/gl_config.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/util/math.hpp>
@@ -11,7 +12,7 @@
#include <cmath>
#include <algorithm>
-using namespace mbgl;
+namespace mbgl {
SpriteAtlas::SpriteAtlas(dimension width_, dimension height_, float pixelRatio_, SpriteStore& store_)
: width(width_),
@@ -142,9 +143,9 @@ void SpriteAtlas::copy(const Holder& holder, const bool wrap) {
dirty = true;
}
-void SpriteAtlas::upload(gl::ObjectStore& objectStore) {
+void SpriteAtlas::upload(gl::ObjectStore& objectStore, gl::Config& config, uint32_t unit) {
if (dirty) {
- bind(false, objectStore);
+ bind(false, objectStore, config, unit);
}
}
@@ -179,14 +180,15 @@ void SpriteAtlas::updateDirty() {
}
}
-void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore) {
+void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore, gl::Config& config, uint32_t unit) {
if (!data) {
return; // Empty atlas
}
if (!texture) {
texture = objectStore.createTexture();
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
+ config.activeTexture = unit;
+ config.texture[unit] = *texture;
#ifndef GL_ES_VERSION_2_0
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
#endif
@@ -195,12 +197,14 @@ void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore) {
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
fullUploadRequired = true;
- } else {
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
+ } else if (config.texture[unit] != *texture) {
+ config.activeTexture = unit;
+ config.texture[unit] = *texture;
}
GLuint filter_val = linear ? GL_LINEAR : GL_NEAREST;
if (filter_val != filter) {
+ config.activeTexture = unit;
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_val));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_val));
filter = filter_val;
@@ -209,6 +213,7 @@ void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore) {
if (dirty) {
std::lock_guard<std::recursive_mutex> lock(mtx);
+ config.activeTexture = unit;
if (fullUploadRequired) {
MBGL_CHECK_ERROR(glTexImage2D(
GL_TEXTURE_2D, // GLenum target
@@ -243,14 +248,15 @@ void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore) {
// pixelWidth, pixelHeight, pixelWidth, pixelHeight);
#endif
}
-};
+}
SpriteAtlas::~SpriteAtlas() = default;
-SpriteAtlas::Holder::Holder(const std::shared_ptr<const SpriteImage>& spriteImage_,
- const Rect<dimension>& pos_)
- : spriteImage(spriteImage_), pos(pos_) {
+SpriteAtlas::Holder::Holder(std::shared_ptr<const SpriteImage> spriteImage_, Rect<dimension> pos_)
+ : spriteImage(std::move(spriteImage_)), pos(std::move(pos_)) {
}
SpriteAtlas::Holder::Holder(Holder&& h) : spriteImage(std::move(h.spriteImage)), pos(h.pos) {
}
+
+} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_atlas.hpp b/src/mbgl/sprite/sprite_atlas.hpp
index 3d91f5c9d8..990ba59e03 100644
--- a/src/mbgl/sprite/sprite_atlas.hpp
+++ b/src/mbgl/sprite/sprite_atlas.hpp
@@ -3,11 +3,11 @@
#include <mbgl/geometry/binpack.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/object_store.hpp>
-#include <mbgl/util/atomic.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/util/optional.hpp>
+#include <atomic>
#include <string>
#include <map>
#include <mutex>
@@ -16,18 +16,18 @@
namespace mbgl {
+namespace gl {
+class Config;
+} // namespace gl
+
class SpriteStore;
class SpriteImage;
class SpritePosition;
struct SpriteAtlasPosition {
- inline SpriteAtlasPosition(const std::array<float, 2> size_ = {{0, 0}},
- const std::array<float, 2> tl_ = {{0, 0}},
- const std::array<float, 2> br_ = {{0, 0}})
- : size(size_), tl(tl_), br(br_) {}
- std::array<float, 2> size;
- std::array<float, 2> tl;
- std::array<float, 2> br;
+ std::array<float, 2> size = {{ 0, 0 }};
+ std::array<float, 2> tl = {{ 0, 0 }};
+ std::array<float, 2> br = {{ 0, 0 }};
};
struct SpriteAtlasElement {
@@ -51,23 +51,23 @@ public:
optional<SpriteAtlasPosition> getPosition(const std::string& name, bool repeating = false);
// Binds the atlas texture to the GPU, and uploads data if it is out of date.
- void bind(bool linear, gl::ObjectStore&);
+ void bind(bool linear, gl::ObjectStore&, gl::Config&, uint32_t unit);
// Updates sprites in the atlas texture that may have changed in the source SpriteStore object.
void updateDirty();
// Uploads the texture to the GPU to be available when we need it. This is a lazy operation;
// the texture is only bound when the data is out of date (=dirty).
- void upload(gl::ObjectStore&);
+ void upload(gl::ObjectStore&, gl::Config&, uint32_t unit);
- inline dimension getWidth() const { return width; }
- inline dimension getHeight() const { return height; }
- inline dimension getTextureWidth() const { return pixelWidth; }
- inline dimension getTextureHeight() const { return pixelHeight; }
- inline float getPixelRatio() const { return pixelRatio; }
+ dimension getWidth() const { return width; }
+ dimension getHeight() const { return height; }
+ dimension getTextureWidth() const { return pixelWidth; }
+ dimension getTextureHeight() const { return pixelHeight; }
+ float getPixelRatio() const { return pixelRatio; }
// Only for use in tests.
- inline const uint32_t* getData() const { return data.get(); }
+ const uint32_t* getData() const { return data.get(); }
private:
const GLsizei width, height;
@@ -75,8 +75,8 @@ private:
const float pixelRatio;
struct Holder : private util::noncopyable {
- inline Holder(const std::shared_ptr<const SpriteImage>&, const Rect<dimension>&);
- inline Holder(Holder&&);
+ Holder(std::shared_ptr<const SpriteImage>, Rect<dimension>);
+ Holder(Holder&&);
std::shared_ptr<const SpriteImage> spriteImage;
const Rect<dimension> pos;
};
@@ -92,7 +92,7 @@ private:
std::map<Key, Holder> images;
std::set<std::string> uninitialized;
std::unique_ptr<uint32_t[]> data;
- util::Atomic<bool> dirty;
+ std::atomic<bool> dirty;
bool fullUploadRequired = true;
mbgl::optional<gl::UniqueTexture> texture;
uint32_t filter = 0;
diff --git a/src/mbgl/sprite/sprite_parser.cpp b/src/mbgl/sprite/sprite_parser.cpp
index 9fbca51112..190ac66e14 100644
--- a/src/mbgl/sprite/sprite_parser.cpp
+++ b/src/mbgl/sprite/sprite_parser.cpp
@@ -46,7 +46,7 @@ SpriteImagePtr createSpriteImage(const PremultipliedImage& image,
namespace {
-inline uint16_t getUInt16(const JSValue& value, const char* name, const uint16_t def = 0) {
+uint16_t getUInt16(const JSValue& value, const char* name, const uint16_t def = 0) {
if (value.HasMember(name)) {
auto& v = value[name];
if (v.IsUint() && v.GetUint() <= std::numeric_limits<uint16_t>::max()) {
@@ -60,7 +60,7 @@ inline uint16_t getUInt16(const JSValue& value, const char* name, const uint16_t
return def;
}
-inline double getDouble(const JSValue& value, const char* name, const double def = 0) {
+double getDouble(const JSValue& value, const char* name, const double def = 0) {
if (value.HasMember(name)) {
auto& v = value[name];
if (v.IsNumber()) {
@@ -73,7 +73,7 @@ inline double getDouble(const JSValue& value, const char* name, const double def
return def;
}
-inline bool getBoolean(const JSValue& value, const char* name, const bool def = false) {
+bool getBoolean(const JSValue& value, const char* name, const bool def = false) {
if (value.HasMember(name)) {
auto& v = value[name];
if (v.IsBool()) {
diff --git a/src/mbgl/storage/network_status.cpp b/src/mbgl/storage/network_status.cpp
index bc538a5f38..1ef5619bd6 100644
--- a/src/mbgl/storage/network_status.cpp
+++ b/src/mbgl/storage/network_status.cpp
@@ -9,7 +9,7 @@
namespace mbgl {
-util::Atomic<bool> NetworkStatus::online(true);
+std::atomic<bool> NetworkStatus::online(true);
std::mutex NetworkStatus::mtx;
std::set<util::AsyncTask *> NetworkStatus::observers;
diff --git a/src/mbgl/storage/resource.cpp b/src/mbgl/storage/resource.cpp
index 3f5b4a3f71..bb587dcc33 100644
--- a/src/mbgl/storage/resource.cpp
+++ b/src/mbgl/storage/resource.cpp
@@ -1,10 +1,44 @@
+#include <mapbox/geometry/box.hpp>
#include <mbgl/storage/resource.hpp>
+#include <mbgl/util/constants.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/token.hpp>
#include <mbgl/util/url.hpp>
+#include <cmath>
+
namespace mbgl {
+static std::string getQuadKey(int32_t x, int32_t y, int8_t z) {
+ std::string quadKey;
+ quadKey.reserve(z);
+ int32_t mask;
+ for (int8_t i = z; i > 0; i--) {
+ mask = 1 << (i - 1);
+ quadKey += '0' + ((x & mask ? 1 : 0) + (y & mask ? 2 : 0));
+ }
+ return quadKey;
+}
+
+static mapbox::geometry::point<double> getMercCoord(int32_t x, int32_t y, int8_t z) {
+ double resolution = (util::M2PI * util::EARTH_RADIUS_M / 256) / std::pow(2.0f, z);
+ return {
+ x * resolution - util::M2PI * util::EARTH_RADIUS_M / 2,
+ y * resolution - util::M2PI * util::EARTH_RADIUS_M / 2,
+ };
+}
+
+static std::string getTileBBox(int32_t x, int32_t y, int8_t z) {
+ // Alter the y for the Google/OSM tile scheme.
+ y = std::pow(2.0f, z) - y - 1;
+
+ auto min = getMercCoord(x * 256, y * 256, z);
+ auto max = getMercCoord((x + 1) * 256, (y + 1) * 256, z);
+
+ return (util::toString(min.x) + "," + util::toString(min.y) + "," +
+ util::toString(max.x) + "," + util::toString(max.y));
+}
+
Resource Resource::style(const std::string& url) {
return Resource {
Resource::Kind::Style,
@@ -64,6 +98,10 @@ Resource Resource::tile(const std::string& urlTemplate,
return util::toString(x);
} else if (token == "y") {
return util::toString(y);
+ } else if (token == "quadkey") {
+ return getQuadKey(x, y, z);
+ } else if (token == "bbox-epsg-3857") {
+ return getTileBBox(x, y, z);
} else if (token == "prefix") {
std::string prefix{ 2 };
prefix[0] = "0123456789abcdef"[x % 16];
@@ -86,4 +124,4 @@ Resource Resource::tile(const std::string& urlTemplate,
};
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/storage/response.cpp b/src/mbgl/storage/response.cpp
index 644d73d286..6809220166 100644
--- a/src/mbgl/storage/response.cpp
+++ b/src/mbgl/storage/response.cpp
@@ -21,14 +21,14 @@ Response& Response::operator=(const Response& res) {
return *this;
}
-Response::Error::Error(Reason reason_, const std::string& message_)
- : reason(reason_), message(message_) {
+Response::Error::Error(Reason reason_, std::string message_)
+ : reason(reason_), message(std::move(message_)) {
}
std::ostream& operator<<(std::ostream& os, Response::Error::Reason r) {
switch (r) {
case Response::Error::Reason::Success:
- return os << "Response::Error::Reason::NotFound";
+ return os << "Response::Error::Reason::Success";
case Response::Error::Reason::NotFound:
return os << "Response::Error::Reason::NotFound";
case Response::Error::Reason::Server:
diff --git a/src/mbgl/style/bucket_parameters.cpp b/src/mbgl/style/bucket_parameters.cpp
index f3367d57e1..64f53babcd 100644
--- a/src/mbgl/style/bucket_parameters.cpp
+++ b/src/mbgl/style/bucket_parameters.cpp
@@ -1,6 +1,6 @@
#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/style/filter_evaluator.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
namespace mbgl {
namespace style {
@@ -10,11 +10,8 @@ void BucketParameters::eachFilteredFeature(const Filter& filter,
auto name = layer.getName();
for (std::size_t i = 0; !cancelled() && i < layer.featureCount(); i++) {
auto feature = layer.getFeature(i);
-
- FilterEvaluator evaluator(*feature);
- if (!Filter::visit(filter, evaluator))
+ if (!filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
continue;
-
function(*feature, i, name);
}
}
diff --git a/src/mbgl/style/bucket_parameters.hpp b/src/mbgl/style/bucket_parameters.hpp
index 8c1da72f25..3b42e7c41b 100644
--- a/src/mbgl/style/bucket_parameters.hpp
+++ b/src/mbgl/style/bucket_parameters.hpp
@@ -3,8 +3,8 @@
#include <mbgl/map/mode.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/style/filter.hpp>
-#include <mbgl/util/atomic.hpp>
+#include <atomic>
#include <functional>
namespace mbgl {
@@ -24,7 +24,7 @@ class BucketParameters {
public:
BucketParameters(const OverscaledTileID& tileID_,
const GeometryTileLayer& layer_,
- const util::Atomic<bool>& obsolete_,
+ const std::atomic<bool>& obsolete_,
uintptr_t tileUID_,
bool& partialParse_,
SpriteStore& spriteStore_,
@@ -51,7 +51,7 @@ public:
const OverscaledTileID& tileID;
const GeometryTileLayer& layer;
- const util::Atomic<bool>& obsolete;
+ const std::atomic<bool>& obsolete;
uintptr_t tileUID;
bool& partialParse;
SpriteStore& spriteStore;
diff --git a/src/mbgl/style/calculation_parameters.hpp b/src/mbgl/style/calculation_parameters.hpp
index 2afd7c4b34..e1f059c524 100644
--- a/src/mbgl/style/calculation_parameters.hpp
+++ b/src/mbgl/style/calculation_parameters.hpp
@@ -12,13 +12,13 @@ public:
: z(z_) {}
CalculationParameters(float z_,
- const TimePoint& now_,
- const ZoomHistory& zoomHistory_,
- const Duration& defaultFadeDuration_)
+ TimePoint now_,
+ ZoomHistory zoomHistory_,
+ Duration defaultFadeDuration_)
: z(z_),
- now(now_),
- zoomHistory(zoomHistory_),
- defaultFadeDuration(defaultFadeDuration_) {}
+ now(std::move(now_)),
+ zoomHistory(std::move(zoomHistory_)),
+ defaultFadeDuration(std::move(defaultFadeDuration_)) {}
float z;
TimePoint now;
diff --git a/src/mbgl/style/cascade_parameters.hpp b/src/mbgl/style/cascade_parameters.hpp
index 4ad6da2ce3..e0333741dd 100644
--- a/src/mbgl/style/cascade_parameters.hpp
+++ b/src/mbgl/style/cascade_parameters.hpp
@@ -9,8 +9,6 @@
namespace mbgl {
namespace style {
-class TransitionOptions;
-
class CascadeParameters {
public:
std::vector<ClassID> classes;
diff --git a/src/mbgl/style/filter_evaluator.hpp b/src/mbgl/style/filter_evaluator.hpp
deleted file mode 100644
index e03beaa4d0..0000000000
--- a/src/mbgl/style/filter_evaluator.hpp
+++ /dev/null
@@ -1,163 +0,0 @@
-#pragma once
-
-#include <mbgl/style/filter.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
-
-#include <type_traits>
-
-namespace mbgl {
-namespace style {
-
-class FilterEvaluator {
-public:
- FilterEvaluator(const GeometryTileFeature& feature_)
- : feature(feature_) {}
-
- bool operator()(const NullFilter&) const {
- return true;
- }
-
- bool operator()(const EqualsFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
- return actual && equal(*actual, filter.value);
- }
-
- bool operator()(const NotEqualsFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
- return !actual || !equal(*actual, filter.value);
- }
-
- bool operator()(const LessThanFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
- return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ < rhs_; });
- }
-
- bool operator()(const LessThanEqualsFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
- return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ <= rhs_; });
- }
-
- bool operator()(const GreaterThanFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
- return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ > rhs_; });
- }
-
- bool operator()(const GreaterThanEqualsFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
- return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ >= rhs_; });
- }
-
- bool operator()(const InFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
- if (!actual)
- return false;
- for (const auto& v: filter.values) {
- if (equal(*actual, v)) {
- return true;
- }
- }
- return false;
- }
-
- bool operator()(const NotInFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
- if (!actual)
- return true;
- for (const auto& v: filter.values) {
- if (equal(*actual, v)) {
- return false;
- }
- }
- return true;
- }
-
- bool operator()(const AnyFilter& filter) const {
- for (const auto& f: filter.filters) {
- if (Filter::visit(f, *this)) {
- return true;
- }
- }
- return false;
- }
-
- bool operator()(const AllFilter& filter) const {
- for (const auto& f: filter.filters) {
- if (!Filter::visit(f, *this)) {
- return false;
- }
- }
- return true;
- }
-
- bool operator()(const NoneFilter& filter) const {
- for (const auto& f: filter.filters) {
- if (Filter::visit(f, *this)) {
- return false;
- }
- }
- return true;
- }
-
- bool operator()(const HasFilter& filter) const {
- return bool(getValue(filter.key));
- }
-
- bool operator()(const NotHasFilter& filter) const {
- return !getValue(filter.key);
- }
-
-private:
- optional<Value> getValue(const std::string& key) const {
- return key == "$type"
- ? optional<Value>(uint64_t(feature.getType()))
- : feature.getValue(key);
- }
-
- template <class Op>
- struct Comparator {
- const Op& op;
-
- template <class T>
- bool operator()(const T& lhs, const T& rhs) const {
- return op(lhs, rhs);
- }
-
- template <class T0, class T1>
- auto operator()(const T0& lhs, const T1& rhs) const
- -> typename std::enable_if_t<std::is_arithmetic<T0>::value && !std::is_same<T0, bool>::value &&
- std::is_arithmetic<T1>::value && !std::is_same<T1, bool>::value, bool> {
- return op(double(lhs), double(rhs));
- }
-
- template <class T0, class T1>
- auto operator()(const T0&, const T1&) const
- -> typename std::enable_if_t<!std::is_arithmetic<T0>::value || std::is_same<T0, bool>::value ||
- !std::is_arithmetic<T1>::value || std::is_same<T1, bool>::value, bool> {
- return false;
- }
-
- bool operator()(const std::vector<Value>&,
- const std::vector<Value>&) const {
- return false;
- }
-
- bool operator()(const std::unordered_map<std::string, Value>&,
- const std::unordered_map<std::string, Value>&) const {
- return false;
- }
- };
-
- template <class Op>
- bool compare(const Value& lhs, const Value& rhs, const Op& op) const {
- return Value::binary_visit(lhs, rhs, Comparator<Op> { op });
- }
-
- bool equal(const Value& lhs, const Value& rhs) const {
- return compare(lhs, rhs, [] (const auto& lhs_, const auto& rhs_) { return lhs_ == rhs_; });
- }
-
- const GeometryTileFeature& feature;
-};
-
-} // namespace mbgl
-} // namespace mbgl
diff --git a/src/mbgl/style/layer.cpp b/src/mbgl/style/layer.cpp
index 342699a2c9..6eff64ae09 100644
--- a/src/mbgl/style/layer.cpp
+++ b/src/mbgl/style/layer.cpp
@@ -38,13 +38,5 @@ void Layer::setMaxZoom(float maxZoom) const {
baseImpl->maxZoom = maxZoom;
}
-std::unique_ptr<Layer> Layer::copy(const std::string& id,
- const std::string& ref) const {
- std::unique_ptr<Layer> result = baseImpl->clone();
- result->baseImpl->id = id;
- result->baseImpl->ref = ref;
- return result;
-}
-
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layer_impl.cpp b/src/mbgl/style/layer_impl.cpp
index 56f66d1789..f50bf87339 100644
--- a/src/mbgl/style/layer_impl.cpp
+++ b/src/mbgl/style/layer_impl.cpp
@@ -3,6 +3,16 @@
namespace mbgl {
namespace style {
+std::unique_ptr<Layer> Layer::Impl::copy(const std::string& id_,
+ const std::string& ref_,
+ const std::string& source_) const {
+ std::unique_ptr<Layer> result = clone();
+ result->baseImpl->id = id_;
+ result->baseImpl->ref = ref_;
+ result->baseImpl->source = source_;
+ return result;
+}
+
const std::string& Layer::Impl::bucketName() const {
return ref.empty() ? id : ref;
}
@@ -12,11 +22,11 @@ bool Layer::Impl::hasRenderPass(RenderPass pass) const {
}
bool Layer::Impl::needsRendering(float zoom) const {
- return passes != RenderPass::None
+ return passes != RenderPass::None
&& visibility != VisibilityType::None
&& minZoom <= zoom
&& maxZoom >= zoom;
- }
+}
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layer_impl.hpp b/src/mbgl/style/layer_impl.hpp
index c84e9b9dea..c1f04fe513 100644
--- a/src/mbgl/style/layer_impl.hpp
+++ b/src/mbgl/style/layer_impl.hpp
@@ -5,8 +5,7 @@
#include <mbgl/style/filter.hpp>
#include <mbgl/renderer/render_pass.hpp>
#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/rapidjson.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <memory>
#include <string>
@@ -37,11 +36,17 @@ class Layer::Impl {
public:
virtual ~Impl() = default;
+ // Create a new layer with the specified `id`, `ref`, and `sourceID`. All other properties
+ // are copied from this layer.
+ std::unique_ptr<Layer> copy(const std::string& id,
+ const std::string& ref,
+ const std::string& sourceID) const;
+
// Create an identical copy of this layer.
virtual std::unique_ptr<Layer> clone() const = 0;
- virtual void parseLayout(const JSValue& value) = 0;
- virtual void parsePaints(const JSValue& value) = 0;
+ // Create a layer, copying all properties except id, ref, and paint properties from this layer.
+ virtual std::unique_ptr<Layer> cloneRef(const std::string& id) const = 0;
// If the layer has a ref, the ref. Otherwise, the id.
const std::string& bucketName() const;
diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp
index aeb4067503..42cd76d01f 100644
--- a/src/mbgl/style/layers/background_layer.cpp
+++ b/src/mbgl/style/layers/background_layer.cpp
@@ -23,6 +23,14 @@ std::unique_ptr<Layer> BackgroundLayer::Impl::clone() const {
return std::make_unique<BackgroundLayer>(*this);
}
+std::unique_ptr<Layer> BackgroundLayer::Impl::cloneRef(const std::string& id_) const {
+ auto result = std::make_unique<BackgroundLayer>(*this);
+ result->impl->id = id_;
+ result->impl->ref = this->id;
+ result->impl->paint = BackgroundPaintProperties();
+ return std::move(result);
+}
+
// Layout properties
@@ -33,24 +41,24 @@ PropertyValue<Color> BackgroundLayer::getBackgroundColor() const {
return impl->paint.backgroundColor.get();
}
-void BackgroundLayer::setBackgroundColor(PropertyValue<Color> value) {
- impl->paint.backgroundColor.set(value);
+void BackgroundLayer::setBackgroundColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+ impl->paint.backgroundColor.set(value, klass);
}
PropertyValue<std::string> BackgroundLayer::getBackgroundPattern() const {
return impl->paint.backgroundPattern.get();
}
-void BackgroundLayer::setBackgroundPattern(PropertyValue<std::string> value) {
- impl->paint.backgroundPattern.set(value);
+void BackgroundLayer::setBackgroundPattern(PropertyValue<std::string> value, const optional<std::string>& klass) {
+ impl->paint.backgroundPattern.set(value, klass);
}
PropertyValue<float> BackgroundLayer::getBackgroundOpacity() const {
return impl->paint.backgroundOpacity.get();
}
-void BackgroundLayer::setBackgroundOpacity(PropertyValue<float> value) {
- impl->paint.backgroundOpacity.set(value);
+void BackgroundLayer::setBackgroundOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.backgroundOpacity.set(value, klass);
}
} // namespace style
diff --git a/src/mbgl/style/layers/background_layer_impl.cpp b/src/mbgl/style/layers/background_layer_impl.cpp
index 0c09c5d158..ea389b828e 100644
--- a/src/mbgl/style/layers/background_layer_impl.cpp
+++ b/src/mbgl/style/layers/background_layer_impl.cpp
@@ -4,10 +4,6 @@
namespace mbgl {
namespace style {
-void BackgroundLayer::Impl::parsePaints(const JSValue& layer) {
- paint.parse(layer);
-}
-
void BackgroundLayer::Impl::cascade(const CascadeParameters& parameters) {
paint.cascade(parameters);
}
diff --git a/src/mbgl/style/layers/background_layer_impl.hpp b/src/mbgl/style/layers/background_layer_impl.hpp
index 19e2a062a4..abbb740f42 100644
--- a/src/mbgl/style/layers/background_layer_impl.hpp
+++ b/src/mbgl/style/layers/background_layer_impl.hpp
@@ -10,9 +10,7 @@ namespace style {
class BackgroundLayer::Impl : public Layer::Impl {
public:
std::unique_ptr<Layer> clone() const override;
-
- void parseLayout(const JSValue&) override {};
- void parsePaints(const JSValue&) override;
+ std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
void cascade(const CascadeParameters&) override;
bool recalculate(const CalculationParameters&) override;
diff --git a/src/mbgl/style/layers/background_layer_properties.cpp b/src/mbgl/style/layers/background_layer_properties.cpp
index a20cedf12c..558093a255 100644
--- a/src/mbgl/style/layers/background_layer_properties.cpp
+++ b/src/mbgl/style/layers/background_layer_properties.cpp
@@ -5,12 +5,6 @@
namespace mbgl {
namespace style {
-void BackgroundPaintProperties::parse(const JSValue& value) {
- backgroundColor.parse("background-color", value);
- backgroundPattern.parse("background-pattern", value);
- backgroundOpacity.parse("background-opacity", value);
-}
-
void BackgroundPaintProperties::cascade(const CascadeParameters& parameters) {
backgroundColor.cascade(parameters);
backgroundPattern.cascade(parameters);
diff --git a/src/mbgl/style/layers/background_layer_properties.hpp b/src/mbgl/style/layers/background_layer_properties.hpp
index a1a1a3a5a7..78a35a4f0c 100644
--- a/src/mbgl/style/layers/background_layer_properties.hpp
+++ b/src/mbgl/style/layers/background_layer_properties.hpp
@@ -2,9 +2,9 @@
#pragma once
+#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
-#include <mbgl/util/rapidjson.hpp>
namespace mbgl {
namespace style {
@@ -14,11 +14,10 @@ class CalculationParameters;
class BackgroundPaintProperties {
public:
- void parse(const JSValue&);
void cascade(const CascadeParameters&);
bool recalculate(const CalculationParameters&);
- PaintProperty<Color> backgroundColor { {{ 0, 0, 0, 1 }} };
+ PaintProperty<Color> backgroundColor { Color::black() };
PaintProperty<std::string, CrossFadedPropertyEvaluator> backgroundPattern { "" };
PaintProperty<float> backgroundOpacity { 1 };
};
diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp
index bdfbf629e6..96cc0b610c 100644
--- a/src/mbgl/style/layers/circle_layer.cpp
+++ b/src/mbgl/style/layers/circle_layer.cpp
@@ -6,10 +6,11 @@
namespace mbgl {
namespace style {
-CircleLayer::CircleLayer(const std::string& layerID)
+CircleLayer::CircleLayer(const std::string& layerID, const std::string& sourceID)
: Layer(Type::Circle, std::make_unique<Impl>())
, impl(static_cast<Impl*>(baseImpl.get())) {
impl->id = layerID;
+ impl->source = sourceID;
}
CircleLayer::CircleLayer(const Impl& other)
@@ -23,17 +24,24 @@ std::unique_ptr<Layer> CircleLayer::Impl::clone() const {
return std::make_unique<CircleLayer>(*this);
}
-// Source
-
-void CircleLayer::setSource(const std::string& sourceID, const std::string& sourceLayer) {
- impl->source = sourceID;
- impl->sourceLayer = sourceLayer;
+std::unique_ptr<Layer> CircleLayer::Impl::cloneRef(const std::string& id_) const {
+ auto result = std::make_unique<CircleLayer>(*this);
+ result->impl->id = id_;
+ result->impl->ref = this->id;
+ result->impl->paint = CirclePaintProperties();
+ return std::move(result);
}
+// Source
+
const std::string& CircleLayer::getSourceID() const {
return impl->source;
}
+void CircleLayer::setSourceLayer(const std::string& sourceLayer) {
+ impl->sourceLayer = sourceLayer;
+}
+
const std::string& CircleLayer::getSourceLayer() const {
return impl->sourceLayer;
}
@@ -57,48 +65,56 @@ PropertyValue<float> CircleLayer::getCircleRadius() const {
return impl->paint.circleRadius.get();
}
-void CircleLayer::setCircleRadius(PropertyValue<float> value) {
- impl->paint.circleRadius.set(value);
+void CircleLayer::setCircleRadius(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.circleRadius.set(value, klass);
}
PropertyValue<Color> CircleLayer::getCircleColor() const {
return impl->paint.circleColor.get();
}
-void CircleLayer::setCircleColor(PropertyValue<Color> value) {
- impl->paint.circleColor.set(value);
+void CircleLayer::setCircleColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+ impl->paint.circleColor.set(value, klass);
}
PropertyValue<float> CircleLayer::getCircleBlur() const {
return impl->paint.circleBlur.get();
}
-void CircleLayer::setCircleBlur(PropertyValue<float> value) {
- impl->paint.circleBlur.set(value);
+void CircleLayer::setCircleBlur(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.circleBlur.set(value, klass);
}
PropertyValue<float> CircleLayer::getCircleOpacity() const {
return impl->paint.circleOpacity.get();
}
-void CircleLayer::setCircleOpacity(PropertyValue<float> value) {
- impl->paint.circleOpacity.set(value);
+void CircleLayer::setCircleOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.circleOpacity.set(value, klass);
}
PropertyValue<std::array<float, 2>> CircleLayer::getCircleTranslate() const {
return impl->paint.circleTranslate.get();
}
-void CircleLayer::setCircleTranslate(PropertyValue<std::array<float, 2>> value) {
- impl->paint.circleTranslate.set(value);
+void CircleLayer::setCircleTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
+ impl->paint.circleTranslate.set(value, klass);
}
PropertyValue<TranslateAnchorType> CircleLayer::getCircleTranslateAnchor() const {
return impl->paint.circleTranslateAnchor.get();
}
-void CircleLayer::setCircleTranslateAnchor(PropertyValue<TranslateAnchorType> value) {
- impl->paint.circleTranslateAnchor.set(value);
+void CircleLayer::setCircleTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
+ impl->paint.circleTranslateAnchor.set(value, klass);
+}
+
+PropertyValue<CirclePitchScaleType> CircleLayer::getCirclePitchScale() const {
+ return impl->paint.circlePitchScale.get();
+}
+
+void CircleLayer::setCirclePitchScale(PropertyValue<CirclePitchScaleType> value, const optional<std::string>& klass) {
+ impl->paint.circlePitchScale.set(value, klass);
}
} // namespace style
diff --git a/src/mbgl/style/layers/circle_layer_impl.cpp b/src/mbgl/style/layers/circle_layer_impl.cpp
index c2efac5cef..e08d9df146 100644
--- a/src/mbgl/style/layers/circle_layer_impl.cpp
+++ b/src/mbgl/style/layers/circle_layer_impl.cpp
@@ -8,10 +8,6 @@
namespace mbgl {
namespace style {
-void CircleLayer::Impl::parsePaints(const JSValue& layer) {
- paint.parse(layer);
-}
-
void CircleLayer::Impl::cascade(const CascadeParameters& parameters) {
paint.cascade(parameters);
}
@@ -19,7 +15,7 @@ void CircleLayer::Impl::cascade(const CascadeParameters& parameters) {
bool CircleLayer::Impl::recalculate(const CalculationParameters& parameters) {
bool hasTransitions = paint.recalculate(parameters);
- passes = (paint.circleRadius > 0 && paint.circleColor.value[3] > 0 && paint.circleOpacity > 0)
+ passes = (paint.circleRadius > 0 && paint.circleColor.value.a > 0 && paint.circleOpacity > 0)
? RenderPass::Translucent : RenderPass::None;
return hasTransitions;
diff --git a/src/mbgl/style/layers/circle_layer_impl.hpp b/src/mbgl/style/layers/circle_layer_impl.hpp
index 463f3ca18d..555691b6b4 100644
--- a/src/mbgl/style/layers/circle_layer_impl.hpp
+++ b/src/mbgl/style/layers/circle_layer_impl.hpp
@@ -10,9 +10,7 @@ namespace style {
class CircleLayer::Impl : public Layer::Impl {
public:
std::unique_ptr<Layer> clone() const override;
-
- void parseLayout(const JSValue&) override {};
- void parsePaints(const JSValue&) override;
+ std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
void cascade(const CascadeParameters&) override;
bool recalculate(const CalculationParameters&) override;
diff --git a/src/mbgl/style/layers/circle_layer_properties.cpp b/src/mbgl/style/layers/circle_layer_properties.cpp
index b21df1e2d0..7243cf87f4 100644
--- a/src/mbgl/style/layers/circle_layer_properties.cpp
+++ b/src/mbgl/style/layers/circle_layer_properties.cpp
@@ -5,15 +5,6 @@
namespace mbgl {
namespace style {
-void CirclePaintProperties::parse(const JSValue& value) {
- circleRadius.parse("circle-radius", value);
- circleColor.parse("circle-color", value);
- circleBlur.parse("circle-blur", value);
- circleOpacity.parse("circle-opacity", value);
- circleTranslate.parse("circle-translate", value);
- circleTranslateAnchor.parse("circle-translate-anchor", value);
-}
-
void CirclePaintProperties::cascade(const CascadeParameters& parameters) {
circleRadius.cascade(parameters);
circleColor.cascade(parameters);
@@ -21,6 +12,7 @@ void CirclePaintProperties::cascade(const CascadeParameters& parameters) {
circleOpacity.cascade(parameters);
circleTranslate.cascade(parameters);
circleTranslateAnchor.cascade(parameters);
+ circlePitchScale.cascade(parameters);
}
bool CirclePaintProperties::recalculate(const CalculationParameters& parameters) {
@@ -32,6 +24,7 @@ bool CirclePaintProperties::recalculate(const CalculationParameters& parameters)
hasTransitions |= circleOpacity.calculate(parameters);
hasTransitions |= circleTranslate.calculate(parameters);
hasTransitions |= circleTranslateAnchor.calculate(parameters);
+ hasTransitions |= circlePitchScale.calculate(parameters);
return hasTransitions;
}
diff --git a/src/mbgl/style/layers/circle_layer_properties.hpp b/src/mbgl/style/layers/circle_layer_properties.hpp
index 956e423c45..0166bc8be4 100644
--- a/src/mbgl/style/layers/circle_layer_properties.hpp
+++ b/src/mbgl/style/layers/circle_layer_properties.hpp
@@ -2,9 +2,9 @@
#pragma once
+#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
-#include <mbgl/util/rapidjson.hpp>
namespace mbgl {
namespace style {
@@ -14,16 +14,16 @@ class CalculationParameters;
class CirclePaintProperties {
public:
- void parse(const JSValue&);
void cascade(const CascadeParameters&);
bool recalculate(const CalculationParameters&);
PaintProperty<float> circleRadius { 5 };
- PaintProperty<Color> circleColor { {{ 0, 0, 0, 1 }} };
+ PaintProperty<Color> circleColor { Color::black() };
PaintProperty<float> circleBlur { 0 };
PaintProperty<float> circleOpacity { 1 };
PaintProperty<std::array<float, 2>> circleTranslate { {{ 0, 0 }} };
PaintProperty<TranslateAnchorType> circleTranslateAnchor { TranslateAnchorType::Map };
+ PaintProperty<CirclePitchScaleType> circlePitchScale { CirclePitchScaleType::Map };
};
} // namespace style
diff --git a/src/mbgl/style/layers/custom_layer_impl.cpp b/src/mbgl/style/layers/custom_layer_impl.cpp
index 214d4ce663..a0686e353c 100644
--- a/src/mbgl/style/layers/custom_layer_impl.cpp
+++ b/src/mbgl/style/layers/custom_layer_impl.cpp
@@ -33,6 +33,11 @@ std::unique_ptr<Layer> CustomLayer::Impl::clone() const {
return std::make_unique<CustomLayer>(*this);
}
+std::unique_ptr<Layer> CustomLayer::Impl::cloneRef(const std::string&) const {
+ assert(false);
+ return std::make_unique<CustomLayer>(*this);
+}
+
void CustomLayer::Impl::initialize() {
assert(initializeFn);
initializeFn(context);
diff --git a/src/mbgl/style/layers/custom_layer_impl.hpp b/src/mbgl/style/layers/custom_layer_impl.hpp
index 00e576b6a3..ffa892ddf8 100644
--- a/src/mbgl/style/layers/custom_layer_impl.hpp
+++ b/src/mbgl/style/layers/custom_layer_impl.hpp
@@ -25,9 +25,7 @@ public:
private:
std::unique_ptr<Layer> clone() const override;
-
- void parseLayout(const JSValue&) final {}
- void parsePaints(const JSValue&) final {}
+ std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
void cascade(const CascadeParameters&) final {}
bool recalculate(const CalculationParameters&) final;
diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp
index 1deaabb5ef..44894aff33 100644
--- a/src/mbgl/style/layers/fill_layer.cpp
+++ b/src/mbgl/style/layers/fill_layer.cpp
@@ -6,10 +6,11 @@
namespace mbgl {
namespace style {
-FillLayer::FillLayer(const std::string& layerID)
+FillLayer::FillLayer(const std::string& layerID, const std::string& sourceID)
: Layer(Type::Fill, std::make_unique<Impl>())
, impl(static_cast<Impl*>(baseImpl.get())) {
impl->id = layerID;
+ impl->source = sourceID;
}
FillLayer::FillLayer(const Impl& other)
@@ -23,17 +24,24 @@ std::unique_ptr<Layer> FillLayer::Impl::clone() const {
return std::make_unique<FillLayer>(*this);
}
-// Source
-
-void FillLayer::setSource(const std::string& sourceID, const std::string& sourceLayer) {
- impl->source = sourceID;
- impl->sourceLayer = sourceLayer;
+std::unique_ptr<Layer> FillLayer::Impl::cloneRef(const std::string& id_) const {
+ auto result = std::make_unique<FillLayer>(*this);
+ result->impl->id = id_;
+ result->impl->ref = this->id;
+ result->impl->paint = FillPaintProperties();
+ return std::move(result);
}
+// Source
+
const std::string& FillLayer::getSourceID() const {
return impl->source;
}
+void FillLayer::setSourceLayer(const std::string& sourceLayer) {
+ impl->sourceLayer = sourceLayer;
+}
+
const std::string& FillLayer::getSourceLayer() const {
return impl->sourceLayer;
}
@@ -57,56 +65,56 @@ PropertyValue<bool> FillLayer::getFillAntialias() const {
return impl->paint.fillAntialias.get();
}
-void FillLayer::setFillAntialias(PropertyValue<bool> value) {
- impl->paint.fillAntialias.set(value);
+void FillLayer::setFillAntialias(PropertyValue<bool> value, const optional<std::string>& klass) {
+ impl->paint.fillAntialias.set(value, klass);
}
PropertyValue<float> FillLayer::getFillOpacity() const {
return impl->paint.fillOpacity.get();
}
-void FillLayer::setFillOpacity(PropertyValue<float> value) {
- impl->paint.fillOpacity.set(value);
+void FillLayer::setFillOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.fillOpacity.set(value, klass);
}
PropertyValue<Color> FillLayer::getFillColor() const {
return impl->paint.fillColor.get();
}
-void FillLayer::setFillColor(PropertyValue<Color> value) {
- impl->paint.fillColor.set(value);
+void FillLayer::setFillColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+ impl->paint.fillColor.set(value, klass);
}
PropertyValue<Color> FillLayer::getFillOutlineColor() const {
return impl->paint.fillOutlineColor.get();
}
-void FillLayer::setFillOutlineColor(PropertyValue<Color> value) {
- impl->paint.fillOutlineColor.set(value);
+void FillLayer::setFillOutlineColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+ impl->paint.fillOutlineColor.set(value, klass);
}
PropertyValue<std::array<float, 2>> FillLayer::getFillTranslate() const {
return impl->paint.fillTranslate.get();
}
-void FillLayer::setFillTranslate(PropertyValue<std::array<float, 2>> value) {
- impl->paint.fillTranslate.set(value);
+void FillLayer::setFillTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
+ impl->paint.fillTranslate.set(value, klass);
}
PropertyValue<TranslateAnchorType> FillLayer::getFillTranslateAnchor() const {
return impl->paint.fillTranslateAnchor.get();
}
-void FillLayer::setFillTranslateAnchor(PropertyValue<TranslateAnchorType> value) {
- impl->paint.fillTranslateAnchor.set(value);
+void FillLayer::setFillTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
+ impl->paint.fillTranslateAnchor.set(value, klass);
}
PropertyValue<std::string> FillLayer::getFillPattern() const {
return impl->paint.fillPattern.get();
}
-void FillLayer::setFillPattern(PropertyValue<std::string> value) {
- impl->paint.fillPattern.set(value);
+void FillLayer::setFillPattern(PropertyValue<std::string> value, const optional<std::string>& klass) {
+ impl->paint.fillPattern.set(value, klass);
}
} // namespace style
diff --git a/src/mbgl/style/layers/fill_layer_impl.cpp b/src/mbgl/style/layers/fill_layer_impl.cpp
index c183617482..2992312514 100644
--- a/src/mbgl/style/layers/fill_layer_impl.cpp
+++ b/src/mbgl/style/layers/fill_layer_impl.cpp
@@ -8,10 +8,6 @@
namespace mbgl {
namespace style {
-void FillLayer::Impl::parsePaints(const JSValue& layer) {
- paint.parse(layer);
-}
-
void FillLayer::Impl::cascade(const CascadeParameters& parameters) {
paint.cascade(parameters);
}
@@ -25,7 +21,7 @@ bool FillLayer::Impl::recalculate(const CalculationParameters& parameters) {
passes |= RenderPass::Translucent;
}
- if (!paint.fillPattern.value.from.empty() || (paint.fillColor.value[3] * paint.fillOpacity) < 1.0f) {
+ if (!paint.fillPattern.value.from.empty() || (paint.fillColor.value.a * paint.fillOpacity) < 1.0f) {
passes |= RenderPass::Translucent;
} else {
passes |= RenderPass::Opaque;
diff --git a/src/mbgl/style/layers/fill_layer_impl.hpp b/src/mbgl/style/layers/fill_layer_impl.hpp
index a37dd76ace..fc6578ecd1 100644
--- a/src/mbgl/style/layers/fill_layer_impl.hpp
+++ b/src/mbgl/style/layers/fill_layer_impl.hpp
@@ -10,9 +10,7 @@ namespace style {
class FillLayer::Impl : public Layer::Impl {
public:
std::unique_ptr<Layer> clone() const override;
-
- void parseLayout(const JSValue&) override {};
- void parsePaints(const JSValue&) override;
+ std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
void cascade(const CascadeParameters&) override;
bool recalculate(const CalculationParameters&) override;
diff --git a/src/mbgl/style/layers/fill_layer_properties.cpp b/src/mbgl/style/layers/fill_layer_properties.cpp
index a4714689f9..9a55cbc145 100644
--- a/src/mbgl/style/layers/fill_layer_properties.cpp
+++ b/src/mbgl/style/layers/fill_layer_properties.cpp
@@ -5,16 +5,6 @@
namespace mbgl {
namespace style {
-void FillPaintProperties::parse(const JSValue& value) {
- fillAntialias.parse("fill-antialias", value);
- fillOpacity.parse("fill-opacity", value);
- fillColor.parse("fill-color", value);
- fillOutlineColor.parse("fill-outline-color", value);
- fillTranslate.parse("fill-translate", value);
- fillTranslateAnchor.parse("fill-translate-anchor", value);
- fillPattern.parse("fill-pattern", value);
-}
-
void FillPaintProperties::cascade(const CascadeParameters& parameters) {
fillAntialias.cascade(parameters);
fillOpacity.cascade(parameters);
diff --git a/src/mbgl/style/layers/fill_layer_properties.hpp b/src/mbgl/style/layers/fill_layer_properties.hpp
index 43396f45d2..d12eb8d6f4 100644
--- a/src/mbgl/style/layers/fill_layer_properties.hpp
+++ b/src/mbgl/style/layers/fill_layer_properties.hpp
@@ -2,9 +2,9 @@
#pragma once
+#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
-#include <mbgl/util/rapidjson.hpp>
namespace mbgl {
namespace style {
@@ -14,14 +14,13 @@ class CalculationParameters;
class FillPaintProperties {
public:
- void parse(const JSValue&);
void cascade(const CascadeParameters&);
bool recalculate(const CalculationParameters&);
PaintProperty<bool> fillAntialias { true };
PaintProperty<float> fillOpacity { 1 };
- PaintProperty<Color> fillColor { {{ 0, 0, 0, 1 }} };
- PaintProperty<Color> fillOutlineColor { {{ 0, 0, 0, -1 }} };
+ PaintProperty<Color> fillColor { Color::black() };
+ PaintProperty<Color> fillOutlineColor { {} };
PaintProperty<std::array<float, 2>> fillTranslate { {{ 0, 0 }} };
PaintProperty<TranslateAnchorType> fillTranslateAnchor { TranslateAnchorType::Map };
PaintProperty<std::string, CrossFadedPropertyEvaluator> fillPattern { "" };
diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs
new file mode 100644
index 0000000000..017691c8ec
--- /dev/null
+++ b/src/mbgl/style/layers/layer.cpp.ejs
@@ -0,0 +1,100 @@
+<%
+ const type = locals.type;
+ const layoutProperties = locals.layoutProperties;
+ const paintProperties = locals.paintProperties;
+-%>
+// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
+
+#include <mbgl/style/layers/<%- type %>_layer.hpp>
+#include <mbgl/style/layers/<%- type %>_layer_impl.hpp>
+
+namespace mbgl {
+namespace style {
+
+<% if (type === 'background') { -%>
+<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const std::string& layerID)
+ : Layer(Type::<%- camelize(type) %>, std::make_unique<Impl>())
+ , impl(static_cast<Impl*>(baseImpl.get())) {
+ impl->id = layerID;
+}
+<% } else { -%>
+<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const std::string& layerID, const std::string& sourceID)
+ : Layer(Type::<%- camelize(type) %>, std::make_unique<Impl>())
+ , impl(static_cast<Impl*>(baseImpl.get())) {
+ impl->id = layerID;
+ impl->source = sourceID;
+}
+<% } -%>
+
+<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const Impl& other)
+ : Layer(Type::<%- camelize(type) %>, std::make_unique<Impl>(other))
+ , impl(static_cast<Impl*>(baseImpl.get())) {
+}
+
+<%- camelize(type) %>Layer::~<%- camelize(type) %>Layer() = default;
+
+std::unique_ptr<Layer> <%- camelize(type) %>Layer::Impl::clone() const {
+ return std::make_unique<<%- camelize(type) %>Layer>(*this);
+}
+
+std::unique_ptr<Layer> <%- camelize(type) %>Layer::Impl::cloneRef(const std::string& id_) const {
+ auto result = std::make_unique<<%- camelize(type) %>Layer>(*this);
+ result->impl->id = id_;
+ result->impl->ref = this->id;
+ result->impl->paint = <%- camelize(type) %>PaintProperties();
+ return std::move(result);
+}
+
+<% if (type !== 'background') { -%>
+// Source
+
+const std::string& <%- camelize(type) %>Layer::getSourceID() const {
+ return impl->source;
+}
+
+<% if (type !== 'raster') { -%>
+void <%- camelize(type) %>Layer::setSourceLayer(const std::string& sourceLayer) {
+ impl->sourceLayer = sourceLayer;
+}
+
+const std::string& <%- camelize(type) %>Layer::getSourceLayer() const {
+ return impl->sourceLayer;
+}
+
+// Filter
+
+void <%- camelize(type) %>Layer::setFilter(const Filter& filter) {
+ impl->filter = filter;
+}
+
+const Filter& <%- camelize(type) %>Layer::getFilter() const {
+ return impl->filter;
+}
+<% } -%>
+<% } -%>
+
+// Layout properties
+
+<% for (const property of layoutProperties) { -%>
+PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const {
+ return impl->layout.<%- camelizeWithLeadingLowercase(property.name) %>.get();
+}
+
+void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value) {
+ impl->layout.<%- camelizeWithLeadingLowercase(property.name) %>.set(value);
+}
+<% } -%>
+
+// Paint properties
+<% for (const property of paintProperties) { %>
+PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const {
+ return impl->paint.<%- camelizeWithLeadingLowercase(property.name) %>.get();
+}
+
+void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value, const optional<std::string>& klass) {
+ impl->paint.<%- camelizeWithLeadingLowercase(property.name) %>.set(value, klass);
+}
+<% } -%>
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layers/layer_properties.cpp.ejs b/src/mbgl/style/layers/layer_properties.cpp.ejs
new file mode 100644
index 0000000000..b781a4a9d9
--- /dev/null
+++ b/src/mbgl/style/layers/layer_properties.cpp.ejs
@@ -0,0 +1,38 @@
+<%
+ const type = locals.type;
+ const layoutProperties = locals.layoutProperties;
+ const paintProperties = locals.paintProperties;
+-%>
+// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
+
+#include <mbgl/style/layers/<%- type %>_layer_properties.hpp>
+
+namespace mbgl {
+namespace style {
+
+<% if (layoutProperties.length) { -%>
+void <%- camelize(type) %>LayoutProperties::recalculate(const CalculationParameters& parameters) {
+<% for (const property of layoutProperties) { -%>
+ <%- camelizeWithLeadingLowercase(property.name) %>.calculate(parameters);
+<% } -%>
+}
+
+<% } -%>
+void <%- camelize(type) %>PaintProperties::cascade(const CascadeParameters& parameters) {
+<% for (const property of paintProperties) { -%>
+ <%- camelizeWithLeadingLowercase(property.name) %>.cascade(parameters);
+<% } -%>
+}
+
+bool <%- camelize(type) %>PaintProperties::recalculate(const CalculationParameters& parameters) {
+ bool hasTransitions = false;
+
+<% for (const property of paintProperties) { -%>
+ hasTransitions |= <%- camelizeWithLeadingLowercase(property.name) %>.calculate(parameters);
+<% } -%>
+
+ return hasTransitions;
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs
new file mode 100644
index 0000000000..6ec92703f1
--- /dev/null
+++ b/src/mbgl/style/layers/layer_properties.hpp.ejs
@@ -0,0 +1,54 @@
+<%
+ const type = locals.type;
+ const layoutProperties = locals.layoutProperties;
+ const paintProperties = locals.paintProperties;
+-%>
+// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
+
+#pragma once
+
+#include <mbgl/style/types.hpp>
+#include <mbgl/style/layout_property.hpp>
+#include <mbgl/style/paint_property.hpp>
+
+namespace mbgl {
+namespace style {
+
+class CascadeParameters;
+class CalculationParameters;
+
+<% if (layoutProperties.length) { -%>
+class <%- camelize(type) %>LayoutProperties {
+public:
+ void recalculate(const CalculationParameters&);
+
+<% for (const property of layoutProperties) { -%>
+ LayoutProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> };
+<% } -%>
+};
+
+<% } -%>
+class <%- camelize(type) %>PaintProperties {
+public:
+ void cascade(const CascadeParameters&);
+ bool recalculate(const CalculationParameters&);
+
+<% for (const property of paintProperties) { -%>
+<% if (/-pattern$/.test(property.name) || property.name === 'line-dasharray') { -%>
+ PaintProperty<<%- propertyType(property) %>, CrossFadedPropertyEvaluator> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> };
+<% } else if (property.name === 'fill-outline-color') { -%>
+ PaintProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { {} };
+<% } else if (property.name.endsWith('color') && defaultValue(property) === '{ 0, 0, 0, 0 }') { -%>
+ PaintProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { {} };
+<% } else if (property.name.endsWith('color') && defaultValue(property) === '{ 0, 0, 0, 1 }') { -%>
+ PaintProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { Color::black() };
+<% } else if (property.name.endsWith('color') && defaultValue(property) === '{ 1, 1, 1, 1 }') { -%>
+ PaintProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { Color::white() };
+<% } else { -%>
+ PaintProperty<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %> { <%- defaultValue(property) %> };
+<% } -%>
+<% } -%>
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp
index abe326a672..3ad72cda16 100644
--- a/src/mbgl/style/layers/line_layer.cpp
+++ b/src/mbgl/style/layers/line_layer.cpp
@@ -6,10 +6,11 @@
namespace mbgl {
namespace style {
-LineLayer::LineLayer(const std::string& layerID)
+LineLayer::LineLayer(const std::string& layerID, const std::string& sourceID)
: Layer(Type::Line, std::make_unique<Impl>())
, impl(static_cast<Impl*>(baseImpl.get())) {
impl->id = layerID;
+ impl->source = sourceID;
}
LineLayer::LineLayer(const Impl& other)
@@ -23,17 +24,24 @@ std::unique_ptr<Layer> LineLayer::Impl::clone() const {
return std::make_unique<LineLayer>(*this);
}
-// Source
-
-void LineLayer::setSource(const std::string& sourceID, const std::string& sourceLayer) {
- impl->source = sourceID;
- impl->sourceLayer = sourceLayer;
+std::unique_ptr<Layer> LineLayer::Impl::cloneRef(const std::string& id_) const {
+ auto result = std::make_unique<LineLayer>(*this);
+ result->impl->id = id_;
+ result->impl->ref = this->id;
+ result->impl->paint = LinePaintProperties();
+ return std::move(result);
}
+// Source
+
const std::string& LineLayer::getSourceID() const {
return impl->source;
}
+void LineLayer::setSourceLayer(const std::string& sourceLayer) {
+ impl->sourceLayer = sourceLayer;
+}
+
const std::string& LineLayer::getSourceLayer() const {
return impl->sourceLayer;
}
@@ -85,80 +93,80 @@ PropertyValue<float> LineLayer::getLineOpacity() const {
return impl->paint.lineOpacity.get();
}
-void LineLayer::setLineOpacity(PropertyValue<float> value) {
- impl->paint.lineOpacity.set(value);
+void LineLayer::setLineOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.lineOpacity.set(value, klass);
}
PropertyValue<Color> LineLayer::getLineColor() const {
return impl->paint.lineColor.get();
}
-void LineLayer::setLineColor(PropertyValue<Color> value) {
- impl->paint.lineColor.set(value);
+void LineLayer::setLineColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+ impl->paint.lineColor.set(value, klass);
}
PropertyValue<std::array<float, 2>> LineLayer::getLineTranslate() const {
return impl->paint.lineTranslate.get();
}
-void LineLayer::setLineTranslate(PropertyValue<std::array<float, 2>> value) {
- impl->paint.lineTranslate.set(value);
+void LineLayer::setLineTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
+ impl->paint.lineTranslate.set(value, klass);
}
PropertyValue<TranslateAnchorType> LineLayer::getLineTranslateAnchor() const {
return impl->paint.lineTranslateAnchor.get();
}
-void LineLayer::setLineTranslateAnchor(PropertyValue<TranslateAnchorType> value) {
- impl->paint.lineTranslateAnchor.set(value);
+void LineLayer::setLineTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
+ impl->paint.lineTranslateAnchor.set(value, klass);
}
PropertyValue<float> LineLayer::getLineWidth() const {
return impl->paint.lineWidth.get();
}
-void LineLayer::setLineWidth(PropertyValue<float> value) {
- impl->paint.lineWidth.set(value);
+void LineLayer::setLineWidth(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.lineWidth.set(value, klass);
}
PropertyValue<float> LineLayer::getLineGapWidth() const {
return impl->paint.lineGapWidth.get();
}
-void LineLayer::setLineGapWidth(PropertyValue<float> value) {
- impl->paint.lineGapWidth.set(value);
+void LineLayer::setLineGapWidth(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.lineGapWidth.set(value, klass);
}
PropertyValue<float> LineLayer::getLineOffset() const {
return impl->paint.lineOffset.get();
}
-void LineLayer::setLineOffset(PropertyValue<float> value) {
- impl->paint.lineOffset.set(value);
+void LineLayer::setLineOffset(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.lineOffset.set(value, klass);
}
PropertyValue<float> LineLayer::getLineBlur() const {
return impl->paint.lineBlur.get();
}
-void LineLayer::setLineBlur(PropertyValue<float> value) {
- impl->paint.lineBlur.set(value);
+void LineLayer::setLineBlur(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.lineBlur.set(value, klass);
}
PropertyValue<std::vector<float>> LineLayer::getLineDasharray() const {
return impl->paint.lineDasharray.get();
}
-void LineLayer::setLineDasharray(PropertyValue<std::vector<float>> value) {
- impl->paint.lineDasharray.set(value);
+void LineLayer::setLineDasharray(PropertyValue<std::vector<float>> value, const optional<std::string>& klass) {
+ impl->paint.lineDasharray.set(value, klass);
}
PropertyValue<std::string> LineLayer::getLinePattern() const {
return impl->paint.linePattern.get();
}
-void LineLayer::setLinePattern(PropertyValue<std::string> value) {
- impl->paint.linePattern.set(value);
+void LineLayer::setLinePattern(PropertyValue<std::string> value, const optional<std::string>& klass) {
+ impl->paint.linePattern.set(value, klass);
}
} // namespace style
diff --git a/src/mbgl/style/layers/line_layer_impl.cpp b/src/mbgl/style/layers/line_layer_impl.cpp
index b7ee9dc5bf..3cdd90b7fd 100644
--- a/src/mbgl/style/layers/line_layer_impl.cpp
+++ b/src/mbgl/style/layers/line_layer_impl.cpp
@@ -8,14 +8,6 @@
namespace mbgl {
namespace style {
-void LineLayer::Impl::parseLayout(const JSValue& value) {
- layout.parse(value);
-}
-
-void LineLayer::Impl::parsePaints(const JSValue& layer) {
- paint.parse(layer);
-}
-
void LineLayer::Impl::cascade(const CascadeParameters& parameters) {
paint.cascade(parameters);
}
@@ -29,7 +21,7 @@ bool LineLayer::Impl::recalculate(const CalculationParameters& parameters) {
bool hasTransitions = paint.recalculate(parameters);
- passes = (paint.lineOpacity > 0 && paint.lineColor.value[3] > 0 && paint.lineWidth > 0)
+ passes = (paint.lineOpacity > 0 && paint.lineColor.value.a > 0 && paint.lineWidth > 0)
? RenderPass::Translucent : RenderPass::None;
return hasTransitions;
diff --git a/src/mbgl/style/layers/line_layer_impl.hpp b/src/mbgl/style/layers/line_layer_impl.hpp
index 3356dc2ceb..e130bc01bc 100644
--- a/src/mbgl/style/layers/line_layer_impl.hpp
+++ b/src/mbgl/style/layers/line_layer_impl.hpp
@@ -10,9 +10,7 @@ namespace style {
class LineLayer::Impl : public Layer::Impl {
public:
std::unique_ptr<Layer> clone() const override;
-
- void parseLayout(const JSValue&) override;
- void parsePaints(const JSValue&) override;
+ std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
void cascade(const CascadeParameters&) override;
bool recalculate(const CalculationParameters&) override;
diff --git a/src/mbgl/style/layers/line_layer_properties.cpp b/src/mbgl/style/layers/line_layer_properties.cpp
index 7c74f6de04..2d6092745e 100644
--- a/src/mbgl/style/layers/line_layer_properties.cpp
+++ b/src/mbgl/style/layers/line_layer_properties.cpp
@@ -5,13 +5,6 @@
namespace mbgl {
namespace style {
-void LineLayoutProperties::parse(const JSValue& value) {
- lineCap.parse("line-cap", value);
- lineJoin.parse("line-join", value);
- lineMiterLimit.parse("line-miter-limit", value);
- lineRoundLimit.parse("line-round-limit", value);
-}
-
void LineLayoutProperties::recalculate(const CalculationParameters& parameters) {
lineCap.calculate(parameters);
lineJoin.calculate(parameters);
@@ -19,19 +12,6 @@ void LineLayoutProperties::recalculate(const CalculationParameters& parameters)
lineRoundLimit.calculate(parameters);
}
-void LinePaintProperties::parse(const JSValue& value) {
- lineOpacity.parse("line-opacity", value);
- lineColor.parse("line-color", value);
- lineTranslate.parse("line-translate", value);
- lineTranslateAnchor.parse("line-translate-anchor", value);
- lineWidth.parse("line-width", value);
- lineGapWidth.parse("line-gap-width", value);
- lineOffset.parse("line-offset", value);
- lineBlur.parse("line-blur", value);
- lineDasharray.parse("line-dasharray", value);
- linePattern.parse("line-pattern", value);
-}
-
void LinePaintProperties::cascade(const CascadeParameters& parameters) {
lineOpacity.cascade(parameters);
lineColor.cascade(parameters);
diff --git a/src/mbgl/style/layers/line_layer_properties.hpp b/src/mbgl/style/layers/line_layer_properties.hpp
index 01a8534222..b73e3f2ef2 100644
--- a/src/mbgl/style/layers/line_layer_properties.hpp
+++ b/src/mbgl/style/layers/line_layer_properties.hpp
@@ -2,9 +2,9 @@
#pragma once
+#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
-#include <mbgl/util/rapidjson.hpp>
namespace mbgl {
namespace style {
@@ -14,7 +14,6 @@ class CalculationParameters;
class LineLayoutProperties {
public:
- void parse(const JSValue&);
void recalculate(const CalculationParameters&);
LayoutProperty<LineCapType> lineCap { LineCapType::Butt };
@@ -25,12 +24,11 @@ public:
class LinePaintProperties {
public:
- void parse(const JSValue&);
void cascade(const CascadeParameters&);
bool recalculate(const CalculationParameters&);
PaintProperty<float> lineOpacity { 1 };
- PaintProperty<Color> lineColor { {{ 0, 0, 0, 1 }} };
+ PaintProperty<Color> lineColor { Color::black() };
PaintProperty<std::array<float, 2>> lineTranslate { {{ 0, 0 }} };
PaintProperty<TranslateAnchorType> lineTranslateAnchor { TranslateAnchorType::Map };
PaintProperty<float> lineWidth { 1 };
diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp
index fb7f08fbe9..d4e121babe 100644
--- a/src/mbgl/style/layers/raster_layer.cpp
+++ b/src/mbgl/style/layers/raster_layer.cpp
@@ -6,10 +6,11 @@
namespace mbgl {
namespace style {
-RasterLayer::RasterLayer(const std::string& layerID)
+RasterLayer::RasterLayer(const std::string& layerID, const std::string& sourceID)
: Layer(Type::Raster, std::make_unique<Impl>())
, impl(static_cast<Impl*>(baseImpl.get())) {
impl->id = layerID;
+ impl->source = sourceID;
}
RasterLayer::RasterLayer(const Impl& other)
@@ -23,16 +24,21 @@ std::unique_ptr<Layer> RasterLayer::Impl::clone() const {
return std::make_unique<RasterLayer>(*this);
}
-// Source
-
-void RasterLayer::setSource(const std::string& sourceID) {
- impl->source = sourceID;
+std::unique_ptr<Layer> RasterLayer::Impl::cloneRef(const std::string& id_) const {
+ auto result = std::make_unique<RasterLayer>(*this);
+ result->impl->id = id_;
+ result->impl->ref = this->id;
+ result->impl->paint = RasterPaintProperties();
+ return std::move(result);
}
+// Source
+
const std::string& RasterLayer::getSourceID() const {
return impl->source;
}
+
// Layout properties
@@ -42,56 +48,56 @@ PropertyValue<float> RasterLayer::getRasterOpacity() const {
return impl->paint.rasterOpacity.get();
}
-void RasterLayer::setRasterOpacity(PropertyValue<float> value) {
- impl->paint.rasterOpacity.set(value);
+void RasterLayer::setRasterOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.rasterOpacity.set(value, klass);
}
PropertyValue<float> RasterLayer::getRasterHueRotate() const {
return impl->paint.rasterHueRotate.get();
}
-void RasterLayer::setRasterHueRotate(PropertyValue<float> value) {
- impl->paint.rasterHueRotate.set(value);
+void RasterLayer::setRasterHueRotate(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.rasterHueRotate.set(value, klass);
}
PropertyValue<float> RasterLayer::getRasterBrightnessMin() const {
return impl->paint.rasterBrightnessMin.get();
}
-void RasterLayer::setRasterBrightnessMin(PropertyValue<float> value) {
- impl->paint.rasterBrightnessMin.set(value);
+void RasterLayer::setRasterBrightnessMin(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.rasterBrightnessMin.set(value, klass);
}
PropertyValue<float> RasterLayer::getRasterBrightnessMax() const {
return impl->paint.rasterBrightnessMax.get();
}
-void RasterLayer::setRasterBrightnessMax(PropertyValue<float> value) {
- impl->paint.rasterBrightnessMax.set(value);
+void RasterLayer::setRasterBrightnessMax(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.rasterBrightnessMax.set(value, klass);
}
PropertyValue<float> RasterLayer::getRasterSaturation() const {
return impl->paint.rasterSaturation.get();
}
-void RasterLayer::setRasterSaturation(PropertyValue<float> value) {
- impl->paint.rasterSaturation.set(value);
+void RasterLayer::setRasterSaturation(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.rasterSaturation.set(value, klass);
}
PropertyValue<float> RasterLayer::getRasterContrast() const {
return impl->paint.rasterContrast.get();
}
-void RasterLayer::setRasterContrast(PropertyValue<float> value) {
- impl->paint.rasterContrast.set(value);
+void RasterLayer::setRasterContrast(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.rasterContrast.set(value, klass);
}
PropertyValue<float> RasterLayer::getRasterFadeDuration() const {
return impl->paint.rasterFadeDuration.get();
}
-void RasterLayer::setRasterFadeDuration(PropertyValue<float> value) {
- impl->paint.rasterFadeDuration.set(value);
+void RasterLayer::setRasterFadeDuration(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.rasterFadeDuration.set(value, klass);
}
} // namespace style
diff --git a/src/mbgl/style/layers/raster_layer_impl.cpp b/src/mbgl/style/layers/raster_layer_impl.cpp
index 4854ec041d..879bfa4559 100644
--- a/src/mbgl/style/layers/raster_layer_impl.cpp
+++ b/src/mbgl/style/layers/raster_layer_impl.cpp
@@ -4,10 +4,6 @@
namespace mbgl {
namespace style {
-void RasterLayer::Impl::parsePaints(const JSValue& layer) {
- paint.parse(layer);
-}
-
void RasterLayer::Impl::cascade(const CascadeParameters& parameters) {
paint.cascade(parameters);
}
diff --git a/src/mbgl/style/layers/raster_layer_impl.hpp b/src/mbgl/style/layers/raster_layer_impl.hpp
index 6812b469a6..a5b396e2ed 100644
--- a/src/mbgl/style/layers/raster_layer_impl.hpp
+++ b/src/mbgl/style/layers/raster_layer_impl.hpp
@@ -10,9 +10,7 @@ namespace style {
class RasterLayer::Impl : public Layer::Impl {
public:
std::unique_ptr<Layer> clone() const override;
-
- void parseLayout(const JSValue&) override {};
- void parsePaints(const JSValue&) override;
+ std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
void cascade(const CascadeParameters&) override;
bool recalculate(const CalculationParameters&) override;
diff --git a/src/mbgl/style/layers/raster_layer_properties.cpp b/src/mbgl/style/layers/raster_layer_properties.cpp
index 0e6afc5e9c..68d9d1d35d 100644
--- a/src/mbgl/style/layers/raster_layer_properties.cpp
+++ b/src/mbgl/style/layers/raster_layer_properties.cpp
@@ -5,16 +5,6 @@
namespace mbgl {
namespace style {
-void RasterPaintProperties::parse(const JSValue& value) {
- rasterOpacity.parse("raster-opacity", value);
- rasterHueRotate.parse("raster-hue-rotate", value);
- rasterBrightnessMin.parse("raster-brightness-min", value);
- rasterBrightnessMax.parse("raster-brightness-max", value);
- rasterSaturation.parse("raster-saturation", value);
- rasterContrast.parse("raster-contrast", value);
- rasterFadeDuration.parse("raster-fade-duration", value);
-}
-
void RasterPaintProperties::cascade(const CascadeParameters& parameters) {
rasterOpacity.cascade(parameters);
rasterHueRotate.cascade(parameters);
diff --git a/src/mbgl/style/layers/raster_layer_properties.hpp b/src/mbgl/style/layers/raster_layer_properties.hpp
index 049da87312..ddfb833e12 100644
--- a/src/mbgl/style/layers/raster_layer_properties.hpp
+++ b/src/mbgl/style/layers/raster_layer_properties.hpp
@@ -2,9 +2,9 @@
#pragma once
+#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
-#include <mbgl/util/rapidjson.hpp>
namespace mbgl {
namespace style {
@@ -14,7 +14,6 @@ class CalculationParameters;
class RasterPaintProperties {
public:
- void parse(const JSValue&);
void cascade(const CascadeParameters&);
bool recalculate(const CalculationParameters&);
diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp
index d7d6a02ace..c26123f0ec 100644
--- a/src/mbgl/style/layers/symbol_layer.cpp
+++ b/src/mbgl/style/layers/symbol_layer.cpp
@@ -6,10 +6,11 @@
namespace mbgl {
namespace style {
-SymbolLayer::SymbolLayer(const std::string& layerID)
+SymbolLayer::SymbolLayer(const std::string& layerID, const std::string& sourceID)
: Layer(Type::Symbol, std::make_unique<Impl>())
, impl(static_cast<Impl*>(baseImpl.get())) {
impl->id = layerID;
+ impl->source = sourceID;
}
SymbolLayer::SymbolLayer(const Impl& other)
@@ -23,17 +24,24 @@ std::unique_ptr<Layer> SymbolLayer::Impl::clone() const {
return std::make_unique<SymbolLayer>(*this);
}
-// Source
-
-void SymbolLayer::setSource(const std::string& sourceID, const std::string& sourceLayer) {
- impl->source = sourceID;
- impl->sourceLayer = sourceLayer;
+std::unique_ptr<Layer> SymbolLayer::Impl::cloneRef(const std::string& id_) const {
+ auto result = std::make_unique<SymbolLayer>(*this);
+ result->impl->id = id_;
+ result->impl->ref = this->id;
+ result->impl->paint = SymbolPaintProperties();
+ return std::move(result);
}
+// Source
+
const std::string& SymbolLayer::getSourceID() const {
return impl->source;
}
+void SymbolLayer::setSourceLayer(const std::string& sourceLayer) {
+ impl->sourceLayer = sourceLayer;
+}
+
const std::string& SymbolLayer::getSourceLayer() const {
return impl->sourceLayer;
}
@@ -92,11 +100,11 @@ PropertyValue<bool> SymbolLayer::getIconOptional() const {
void SymbolLayer::setIconOptional(PropertyValue<bool> value) {
impl->layout.iconOptional.set(value);
}
-PropertyValue<RotationAlignmentType> SymbolLayer::getIconRotationAlignment() const {
+PropertyValue<AlignmentType> SymbolLayer::getIconRotationAlignment() const {
return impl->layout.iconRotationAlignment.get();
}
-void SymbolLayer::setIconRotationAlignment(PropertyValue<RotationAlignmentType> value) {
+void SymbolLayer::setIconRotationAlignment(PropertyValue<AlignmentType> value) {
impl->layout.iconRotationAlignment.set(value);
}
PropertyValue<float> SymbolLayer::getIconSize() const {
@@ -106,6 +114,20 @@ PropertyValue<float> SymbolLayer::getIconSize() const {
void SymbolLayer::setIconSize(PropertyValue<float> value) {
impl->layout.iconSize.set(value);
}
+PropertyValue<IconTextFitType> SymbolLayer::getIconTextFit() const {
+ return impl->layout.iconTextFit.get();
+}
+
+void SymbolLayer::setIconTextFit(PropertyValue<IconTextFitType> value) {
+ impl->layout.iconTextFit.set(value);
+}
+PropertyValue<std::array<float, 4>> SymbolLayer::getIconTextFitPadding() const {
+ return impl->layout.iconTextFitPadding.get();
+}
+
+void SymbolLayer::setIconTextFitPadding(PropertyValue<std::array<float, 4>> value) {
+ impl->layout.iconTextFitPadding.set(value);
+}
PropertyValue<std::string> SymbolLayer::getIconImage() const {
return impl->layout.iconImage.get();
}
@@ -141,11 +163,18 @@ PropertyValue<std::array<float, 2>> SymbolLayer::getIconOffset() const {
void SymbolLayer::setIconOffset(PropertyValue<std::array<float, 2>> value) {
impl->layout.iconOffset.set(value);
}
-PropertyValue<RotationAlignmentType> SymbolLayer::getTextRotationAlignment() const {
+PropertyValue<AlignmentType> SymbolLayer::getTextPitchAlignment() const {
+ return impl->layout.textPitchAlignment.get();
+}
+
+void SymbolLayer::setTextPitchAlignment(PropertyValue<AlignmentType> value) {
+ impl->layout.textPitchAlignment.set(value);
+}
+PropertyValue<AlignmentType> SymbolLayer::getTextRotationAlignment() const {
return impl->layout.textRotationAlignment.get();
}
-void SymbolLayer::setTextRotationAlignment(PropertyValue<RotationAlignmentType> value) {
+void SymbolLayer::setTextRotationAlignment(PropertyValue<AlignmentType> value) {
impl->layout.textRotationAlignment.set(value);
}
PropertyValue<std::string> SymbolLayer::getTextField() const {
@@ -274,112 +303,112 @@ PropertyValue<float> SymbolLayer::getIconOpacity() const {
return impl->paint.iconOpacity.get();
}
-void SymbolLayer::setIconOpacity(PropertyValue<float> value) {
- impl->paint.iconOpacity.set(value);
+void SymbolLayer::setIconOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.iconOpacity.set(value, klass);
}
PropertyValue<Color> SymbolLayer::getIconColor() const {
return impl->paint.iconColor.get();
}
-void SymbolLayer::setIconColor(PropertyValue<Color> value) {
- impl->paint.iconColor.set(value);
+void SymbolLayer::setIconColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+ impl->paint.iconColor.set(value, klass);
}
PropertyValue<Color> SymbolLayer::getIconHaloColor() const {
return impl->paint.iconHaloColor.get();
}
-void SymbolLayer::setIconHaloColor(PropertyValue<Color> value) {
- impl->paint.iconHaloColor.set(value);
+void SymbolLayer::setIconHaloColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+ impl->paint.iconHaloColor.set(value, klass);
}
PropertyValue<float> SymbolLayer::getIconHaloWidth() const {
return impl->paint.iconHaloWidth.get();
}
-void SymbolLayer::setIconHaloWidth(PropertyValue<float> value) {
- impl->paint.iconHaloWidth.set(value);
+void SymbolLayer::setIconHaloWidth(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.iconHaloWidth.set(value, klass);
}
PropertyValue<float> SymbolLayer::getIconHaloBlur() const {
return impl->paint.iconHaloBlur.get();
}
-void SymbolLayer::setIconHaloBlur(PropertyValue<float> value) {
- impl->paint.iconHaloBlur.set(value);
+void SymbolLayer::setIconHaloBlur(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.iconHaloBlur.set(value, klass);
}
PropertyValue<std::array<float, 2>> SymbolLayer::getIconTranslate() const {
return impl->paint.iconTranslate.get();
}
-void SymbolLayer::setIconTranslate(PropertyValue<std::array<float, 2>> value) {
- impl->paint.iconTranslate.set(value);
+void SymbolLayer::setIconTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
+ impl->paint.iconTranslate.set(value, klass);
}
PropertyValue<TranslateAnchorType> SymbolLayer::getIconTranslateAnchor() const {
return impl->paint.iconTranslateAnchor.get();
}
-void SymbolLayer::setIconTranslateAnchor(PropertyValue<TranslateAnchorType> value) {
- impl->paint.iconTranslateAnchor.set(value);
+void SymbolLayer::setIconTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
+ impl->paint.iconTranslateAnchor.set(value, klass);
}
PropertyValue<float> SymbolLayer::getTextOpacity() const {
return impl->paint.textOpacity.get();
}
-void SymbolLayer::setTextOpacity(PropertyValue<float> value) {
- impl->paint.textOpacity.set(value);
+void SymbolLayer::setTextOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.textOpacity.set(value, klass);
}
PropertyValue<Color> SymbolLayer::getTextColor() const {
return impl->paint.textColor.get();
}
-void SymbolLayer::setTextColor(PropertyValue<Color> value) {
- impl->paint.textColor.set(value);
+void SymbolLayer::setTextColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+ impl->paint.textColor.set(value, klass);
}
PropertyValue<Color> SymbolLayer::getTextHaloColor() const {
return impl->paint.textHaloColor.get();
}
-void SymbolLayer::setTextHaloColor(PropertyValue<Color> value) {
- impl->paint.textHaloColor.set(value);
+void SymbolLayer::setTextHaloColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+ impl->paint.textHaloColor.set(value, klass);
}
PropertyValue<float> SymbolLayer::getTextHaloWidth() const {
return impl->paint.textHaloWidth.get();
}
-void SymbolLayer::setTextHaloWidth(PropertyValue<float> value) {
- impl->paint.textHaloWidth.set(value);
+void SymbolLayer::setTextHaloWidth(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.textHaloWidth.set(value, klass);
}
PropertyValue<float> SymbolLayer::getTextHaloBlur() const {
return impl->paint.textHaloBlur.get();
}
-void SymbolLayer::setTextHaloBlur(PropertyValue<float> value) {
- impl->paint.textHaloBlur.set(value);
+void SymbolLayer::setTextHaloBlur(PropertyValue<float> value, const optional<std::string>& klass) {
+ impl->paint.textHaloBlur.set(value, klass);
}
PropertyValue<std::array<float, 2>> SymbolLayer::getTextTranslate() const {
return impl->paint.textTranslate.get();
}
-void SymbolLayer::setTextTranslate(PropertyValue<std::array<float, 2>> value) {
- impl->paint.textTranslate.set(value);
+void SymbolLayer::setTextTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) {
+ impl->paint.textTranslate.set(value, klass);
}
PropertyValue<TranslateAnchorType> SymbolLayer::getTextTranslateAnchor() const {
return impl->paint.textTranslateAnchor.get();
}
-void SymbolLayer::setTextTranslateAnchor(PropertyValue<TranslateAnchorType> value) {
- impl->paint.textTranslateAnchor.set(value);
+void SymbolLayer::setTextTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) {
+ impl->paint.textTranslateAnchor.set(value, klass);
}
} // namespace style
diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp
index a4dc264ed2..0243b1dfa5 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.cpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.cpp
@@ -5,14 +5,6 @@
namespace mbgl {
namespace style {
-void SymbolLayer::Impl::parseLayout(const JSValue& value) {
- layout.parse(value);
-}
-
-void SymbolLayer::Impl::parsePaints(const JSValue& layer) {
- paint.parse(layer);
-}
-
void SymbolLayer::Impl::cascade(const CascadeParameters& parameters) {
paint.cascade(parameters);
}
@@ -26,8 +18,8 @@ bool SymbolLayer::Impl::recalculate(const CalculationParameters& parameters) {
iconSize = layout.iconSize;
textSize = layout.textSize;
- passes = ((paint.iconOpacity > 0 && (paint.iconColor.value[3] > 0 || paint.iconHaloColor.value[3] > 0) && iconSize > 0)
- || (paint.textOpacity > 0 && (paint.textColor.value[3] > 0 || paint.textHaloColor.value[3] > 0) && textSize > 0))
+ passes = ((paint.iconOpacity > 0 && (paint.iconColor.value.a > 0 || paint.iconHaloColor.value.a > 0) && iconSize > 0)
+ || (paint.textOpacity > 0 && (paint.textColor.value.a > 0 || paint.textHaloColor.value.a > 0) && textSize > 0))
? RenderPass::Translucent : RenderPass::None;
return hasTransitions;
@@ -45,8 +37,13 @@ std::unique_ptr<Bucket> SymbolLayer::Impl::createBucket(BucketParameters& parame
CalculationParameters p(parameters.tileID.overscaledZ);
bucket->layout.symbolPlacement.calculate(p);
if (bucket->layout.symbolPlacement.value == SymbolPlacementType::Line) {
- bucket->layout.iconRotationAlignment.value = RotationAlignmentType::Map;
- bucket->layout.textRotationAlignment.value = RotationAlignmentType::Map;
+ bucket->layout.iconRotationAlignment.value = AlignmentType::Map;
+ bucket->layout.textRotationAlignment.value = AlignmentType::Map;
+ };
+
+ // If unspecified `text-pitch-alignment` inherits `text-rotation-alignment`
+ if (bucket->layout.textPitchAlignment.value == AlignmentType::Undefined) {
+ bucket->layout.textPitchAlignment.value = bucket->layout.textRotationAlignment.value;
};
bucket->layout.recalculate(p);
diff --git a/src/mbgl/style/layers/symbol_layer_impl.hpp b/src/mbgl/style/layers/symbol_layer_impl.hpp
index 9727cc6480..7765d6790e 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.hpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.hpp
@@ -13,9 +13,7 @@ namespace style {
class SymbolLayer::Impl : public Layer::Impl {
public:
std::unique_ptr<Layer> clone() const override;
-
- void parseLayout(const JSValue&) override;
- void parsePaints(const JSValue&) override;
+ std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
void cascade(const CascadeParameters&) override;
bool recalculate(const CalculationParameters&) override;
diff --git a/src/mbgl/style/layers/symbol_layer_properties.cpp b/src/mbgl/style/layers/symbol_layer_properties.cpp
index ce16ae2e50..59a73d3d59 100644
--- a/src/mbgl/style/layers/symbol_layer_properties.cpp
+++ b/src/mbgl/style/layers/symbol_layer_properties.cpp
@@ -5,40 +5,6 @@
namespace mbgl {
namespace style {
-void SymbolLayoutProperties::parse(const JSValue& value) {
- symbolPlacement.parse("symbol-placement", value);
- symbolSpacing.parse("symbol-spacing", value);
- symbolAvoidEdges.parse("symbol-avoid-edges", value);
- iconAllowOverlap.parse("icon-allow-overlap", value);
- iconIgnorePlacement.parse("icon-ignore-placement", value);
- iconOptional.parse("icon-optional", value);
- iconRotationAlignment.parse("icon-rotation-alignment", value);
- iconSize.parse("icon-size", value);
- iconImage.parse("icon-image", value);
- iconRotate.parse("icon-rotate", value);
- iconPadding.parse("icon-padding", value);
- iconKeepUpright.parse("icon-keep-upright", value);
- iconOffset.parse("icon-offset", value);
- textRotationAlignment.parse("text-rotation-alignment", value);
- textField.parse("text-field", value);
- textFont.parse("text-font", value);
- textSize.parse("text-size", value);
- textMaxWidth.parse("text-max-width", value);
- textLineHeight.parse("text-line-height", value);
- textLetterSpacing.parse("text-letter-spacing", value);
- textJustify.parse("text-justify", value);
- textAnchor.parse("text-anchor", value);
- textMaxAngle.parse("text-max-angle", value);
- textRotate.parse("text-rotate", value);
- textPadding.parse("text-padding", value);
- textKeepUpright.parse("text-keep-upright", value);
- textTransform.parse("text-transform", value);
- textOffset.parse("text-offset", value);
- textAllowOverlap.parse("text-allow-overlap", value);
- textIgnorePlacement.parse("text-ignore-placement", value);
- textOptional.parse("text-optional", value);
-}
-
void SymbolLayoutProperties::recalculate(const CalculationParameters& parameters) {
symbolPlacement.calculate(parameters);
symbolSpacing.calculate(parameters);
@@ -48,11 +14,14 @@ void SymbolLayoutProperties::recalculate(const CalculationParameters& parameters
iconOptional.calculate(parameters);
iconRotationAlignment.calculate(parameters);
iconSize.calculate(parameters);
+ iconTextFit.calculate(parameters);
+ iconTextFitPadding.calculate(parameters);
iconImage.calculate(parameters);
iconRotate.calculate(parameters);
iconPadding.calculate(parameters);
iconKeepUpright.calculate(parameters);
iconOffset.calculate(parameters);
+ textPitchAlignment.calculate(parameters);
textRotationAlignment.calculate(parameters);
textField.calculate(parameters);
textFont.calculate(parameters);
@@ -73,23 +42,6 @@ void SymbolLayoutProperties::recalculate(const CalculationParameters& parameters
textOptional.calculate(parameters);
}
-void SymbolPaintProperties::parse(const JSValue& value) {
- iconOpacity.parse("icon-opacity", value);
- iconColor.parse("icon-color", value);
- iconHaloColor.parse("icon-halo-color", value);
- iconHaloWidth.parse("icon-halo-width", value);
- iconHaloBlur.parse("icon-halo-blur", value);
- iconTranslate.parse("icon-translate", value);
- iconTranslateAnchor.parse("icon-translate-anchor", value);
- textOpacity.parse("text-opacity", value);
- textColor.parse("text-color", value);
- textHaloColor.parse("text-halo-color", value);
- textHaloWidth.parse("text-halo-width", value);
- textHaloBlur.parse("text-halo-blur", value);
- textTranslate.parse("text-translate", value);
- textTranslateAnchor.parse("text-translate-anchor", value);
-}
-
void SymbolPaintProperties::cascade(const CascadeParameters& parameters) {
iconOpacity.cascade(parameters);
iconColor.cascade(parameters);
diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp
index 38455b5cac..e4560ab486 100644
--- a/src/mbgl/style/layers/symbol_layer_properties.hpp
+++ b/src/mbgl/style/layers/symbol_layer_properties.hpp
@@ -2,9 +2,9 @@
#pragma once
+#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
-#include <mbgl/util/rapidjson.hpp>
namespace mbgl {
namespace style {
@@ -14,7 +14,6 @@ class CalculationParameters;
class SymbolLayoutProperties {
public:
- void parse(const JSValue&);
void recalculate(const CalculationParameters&);
LayoutProperty<SymbolPlacementType> symbolPlacement { SymbolPlacementType::Point };
@@ -23,14 +22,17 @@ public:
LayoutProperty<bool> iconAllowOverlap { false };
LayoutProperty<bool> iconIgnorePlacement { false };
LayoutProperty<bool> iconOptional { false };
- LayoutProperty<RotationAlignmentType> iconRotationAlignment { RotationAlignmentType::Viewport };
+ LayoutProperty<AlignmentType> iconRotationAlignment { AlignmentType::Viewport };
LayoutProperty<float> iconSize { 1 };
+ LayoutProperty<IconTextFitType> iconTextFit { IconTextFitType::None };
+ LayoutProperty<std::array<float, 4>> iconTextFitPadding { {{ 0, 0, 0, 0 }} };
LayoutProperty<std::string> iconImage { "" };
LayoutProperty<float> iconRotate { 0 };
LayoutProperty<float> iconPadding { 2 };
LayoutProperty<bool> iconKeepUpright { false };
LayoutProperty<std::array<float, 2>> iconOffset { {{ 0, 0 }} };
- LayoutProperty<RotationAlignmentType> textRotationAlignment { RotationAlignmentType::Viewport };
+ LayoutProperty<AlignmentType> textPitchAlignment { AlignmentType::Undefined };
+ LayoutProperty<AlignmentType> textRotationAlignment { AlignmentType::Viewport };
LayoutProperty<std::string> textField { "" };
LayoutProperty<std::vector<std::string>> textFont { { "Open Sans Regular", "Arial Unicode MS Regular" } };
LayoutProperty<float> textSize { 16 };
@@ -52,20 +54,19 @@ public:
class SymbolPaintProperties {
public:
- void parse(const JSValue&);
void cascade(const CascadeParameters&);
bool recalculate(const CalculationParameters&);
PaintProperty<float> iconOpacity { 1 };
- PaintProperty<Color> iconColor { {{ 0, 0, 0, 1 }} };
- PaintProperty<Color> iconHaloColor { {{ 0, 0, 0, 0 }} };
+ PaintProperty<Color> iconColor { Color::black() };
+ PaintProperty<Color> iconHaloColor { {} };
PaintProperty<float> iconHaloWidth { 0 };
PaintProperty<float> iconHaloBlur { 0 };
PaintProperty<std::array<float, 2>> iconTranslate { {{ 0, 0 }} };
PaintProperty<TranslateAnchorType> iconTranslateAnchor { TranslateAnchorType::Map };
PaintProperty<float> textOpacity { 1 };
- PaintProperty<Color> textColor { {{ 0, 0, 0, 1 }} };
- PaintProperty<Color> textHaloColor { {{ 0, 0, 0, 0 }} };
+ PaintProperty<Color> textColor { Color::black() };
+ PaintProperty<Color> textHaloColor { {} };
PaintProperty<float> textHaloWidth { 0 };
PaintProperty<float> textHaloBlur { 0 };
PaintProperty<std::array<float, 2>> textTranslate { {{ 0, 0 }} };
diff --git a/src/mbgl/style/layout_property.hpp b/src/mbgl/style/layout_property.hpp
index f5045b47fc..db1a1ebf28 100644
--- a/src/mbgl/style/layout_property.hpp
+++ b/src/mbgl/style/layout_property.hpp
@@ -3,7 +3,6 @@
#include <mbgl/style/property_value.hpp>
#include <mbgl/style/property_parsing.hpp>
#include <mbgl/style/property_evaluator.hpp>
-#include <mbgl/util/rapidjson.hpp>
#include <utility>
@@ -25,12 +24,6 @@ public:
currentValue = value_;
}
- void parse(const char * name, const JSValue& layout) {
- if (layout.HasMember(name)) {
- currentValue = parseProperty<T>(name, layout[name]);
- }
- }
-
void calculate(const CalculationParameters& parameters) {
if (currentValue) {
PropertyEvaluator<T> evaluator(parameters, defaultValue);
diff --git a/src/mbgl/style/observer.hpp b/src/mbgl/style/observer.hpp
index c19f58904f..2c48114669 100644
--- a/src/mbgl/style/observer.hpp
+++ b/src/mbgl/style/observer.hpp
@@ -15,10 +15,10 @@ public:
* In addition to the individual glyph, sprite, and source events, the
* following "rollup" events are provided for convenience. They are
* strictly additive; e.g. when a source is loaded, both `onSourceLoaded`
- * and `onResourceLoaded` will be called.
+ * and `onNeedsRepaint` will be called.
*/
- virtual void onResourceLoaded() {};
- virtual void onResourceError(std::exception_ptr) {};
+ void onNeedsRepaint() override {}
+ virtual void onResourceError(std::exception_ptr) {}
};
} // namespace style
diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp
index 62fd59684e..6da1ed53b4 100644
--- a/src/mbgl/style/paint_property.hpp
+++ b/src/mbgl/style/paint_property.hpp
@@ -6,8 +6,8 @@
#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/cascade_parameters.hpp>
#include <mbgl/style/calculation_parameters.hpp>
+#include <mbgl/util/constants.hpp>
#include <mbgl/util/interpolate.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/rapidjson.hpp>
#include <map>
@@ -27,47 +27,34 @@ public:
}
PaintProperty(const PaintProperty& other)
- : values(other.values),
+ : defaultValue(other.defaultValue),
+ values(other.values),
transitions(other.transitions) {
}
- const PropertyValue<T>& get() const {
- return values.at(ClassID::Default);
+ PaintProperty& operator=(const PaintProperty& other) {
+ defaultValue = other.defaultValue;
+ values = other.values;
+ transitions = other.transitions;
+ return *this;
}
- void set(const PropertyValue<T>& value_) {
- values.emplace(ClassID::Default, value_);
+ bool isUndefined() const {
+ return values.find(ClassID::Default) == values.end();
}
- void parse(const char* name, const JSValue& layer) {
- mbgl::util::erase_if(values, [] (const auto& p) { return p.first != ClassID::Fallback; });
-
- std::string transitionName = { name };
- transitionName += "-transition";
-
- for (auto it = layer.MemberBegin(); it != layer.MemberEnd(); ++it) {
- const std::string paintName { it->name.GetString(), it->name.GetStringLength() };
- if (paintName.compare(0, 5, "paint") != 0)
- continue;
-
- bool isClass = paintName.compare(0, 6, "paint.") == 0;
- if (isClass && paintName.length() <= 6)
- continue;
-
- ClassID classID = isClass ? ClassDictionary::Get().lookup(paintName.substr(6)) : ClassID::Default;
+ const PropertyValue<T>& get() const {
+ static const PropertyValue<T> staticValue;
+ const auto it = values.find(ClassID::Default);
+ return it == values.end() ? staticValue : it->second;
+ }
- if (it->value.HasMember(name)) {
- if (auto v = parseProperty<T>(name, it->value[name])) {
- values.emplace(classID, v);
- }
- }
+ void set(const PropertyValue<T>& value_, const optional<std::string>& klass) {
+ values[klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default] = value_;
+ }
- if (it->value.HasMember(transitionName.c_str())) {
- if (auto v = parseTransitionOptions(name, it->value[transitionName.c_str()])) {
- transitions.emplace(classID, *v);
- }
- }
- }
+ void setTransition(const TransitionOptions& transition, const optional<std::string>& klass) {
+ transitions[klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default] = transition;
}
void cascade(const CascadeParameters& params) {
@@ -118,24 +105,24 @@ private:
TimePoint end_,
PropertyValue<T> value_)
: prior(std::move(prior_)),
- begin(begin_),
- end(end_),
+ begin(std::move(begin_)),
+ end(std::move(end_)),
value(std::move(value_)) {
}
Result calculate(const Evaluator<T>& evaluator, const TimePoint& now) {
- Result final = PropertyValue<T>::visit(value, evaluator);
+ Result finalValue = PropertyValue<T>::visit(value, evaluator);
if (!prior) {
// No prior value.
- return final;
+ return finalValue;
} else if (now >= end) {
// Transition from prior value is now complete.
prior.reset();
- return final;
+ return finalValue;
} else {
// Interpolate between recursively-calculated prior value and final.
float t = std::chrono::duration<float>(now - begin) / (end - begin);
- return util::interpolate(prior->calculate(evaluator, now), final, t);
+ return util::interpolate(prior->calculate(evaluator, now), finalValue, util::DEFAULT_TRANSITION_EASE.solve(t, 0.001));
}
}
diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp
index 28a7d2e81b..2746b8af92 100644
--- a/src/mbgl/style/parser.cpp
+++ b/src/mbgl/style/parser.cpp
@@ -1,107 +1,23 @@
#include <mbgl/style/parser.hpp>
#include <mbgl/style/layer_impl.hpp>
-#include <mbgl/style/layers/fill_layer.hpp>
-#include <mbgl/style/layers/line_layer.hpp>
-#include <mbgl/style/layers/circle_layer.hpp>
-#include <mbgl/style/layers/symbol_layer.hpp>
-#include <mbgl/style/layers/raster_layer.hpp>
-#include <mbgl/style/layers/background_layer.hpp>
+#include <mbgl/style/rapidjson_conversion.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/source.hpp>
+#include <mbgl/style/conversion/layer.hpp>
#include <mbgl/platform/log.hpp>
#include <mapbox/geojsonvt.hpp>
-#include <mapbox/geojsonvt/convert.hpp>
-
-#include <mbgl/tile/geometry_tile.hpp>
-#include <mbgl/util/mapbox.hpp>
#include <rapidjson/document.h>
#include <rapidjson/error/en.h>
#include <algorithm>
-#include <sstream>
#include <set>
namespace mbgl {
namespace style {
-namespace {
-
-void parseTileJSONMember(const JSValue& value, std::vector<std::string>& target, const char* name) {
- if (!value.HasMember(name)) {
- return;
- }
-
- const JSValue& property = value[name];
- if (!property.IsArray()) {
- return;
- }
-
- for (rapidjson::SizeType i = 0; i < property.Size(); i++) {
- if (!property[i].IsString()) {
- return;
- }
- }
-
- for (rapidjson::SizeType i = 0; i < property.Size(); i++) {
- target.emplace_back(std::string(property[i].GetString(), property[i].GetStringLength()));
- }
-}
-
-void parseTileJSONMember(const JSValue& value, std::string& target, const char* name) {
- if (!value.HasMember(name)) {
- return;
- }
-
- const JSValue& property = value[name];
- if (!property.IsString()) {
- return;
- }
-
- target = { property.GetString(), property.GetStringLength() };
-}
-
-void parseTileJSONMember(const JSValue& value, uint8_t& target, const char* name) {
- if (!value.HasMember(name)) {
- return;
- }
-
- const JSValue& property = value[name];
- if (!property.IsUint()) {
- return;
- }
-
- unsigned int uint = property.GetUint();
- if (uint > std::numeric_limits<uint8_t>::max()) {
- return;
- }
-
- target = uint;
-}
-
-void parseTileJSONMember(const JSValue& value, std::array<double, 4>& target, const char* name) {
- if (!value.HasMember(name)) {
- return;
- }
-
- const JSValue& property = value[name];
- if (!property.IsArray() || property.Size() > 4) {
- return;
- }
-
- for (rapidjson::SizeType i = 0; i < property.Size(); i++) {
- if (!property[i].IsNumber()) {
- return;
- }
- }
-
- for (rapidjson::SizeType i = 0; i < property.Size(); i++) {
- target[i] = property[i].GetDouble();
- }
-}
-
-} // end namespace
-
Parser::~Parser() = default;
void Parser::parse(const std::string& json) {
@@ -113,8 +29,14 @@ void Parser::parse(const std::string& json) {
return;
}
+ if (!document.IsObject()) {
+ Log::Error(Event::ParseStyle, "Style JSON must be an object");
+ return;
+ }
+
if (document.HasMember("version")) {
- int version = document["version"].GetInt();
+ const JSValue& versionValue = document["version"];
+ const int version = versionValue.IsNumber() ? versionValue.GetInt() : 0;
if (version != 8) {
Log::Warning(Event::ParseStyle, "current renderer implementation only supports style spec version 8; using an outdated style will cause rendering errors");
}
@@ -149,154 +71,19 @@ void Parser::parseSources(const JSValue& value) {
return;
}
- JSValue::ConstMemberIterator itr = value.MemberBegin();
- for (; itr != value.MemberEnd(); ++itr) {
- const JSValue& nameVal = itr->name;
- const JSValue& sourceVal = itr->value;
-
- if (!sourceVal.HasMember("type")) {
- Log::Warning(Event::ParseStyle, "source must have a type");
- continue;
- }
+ for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it) {
+ std::string id = *conversion::toString(it->name);
- const JSValue& typeVal = sourceVal["type"];
- if (!typeVal.IsString()) {
- Log::Warning(Event::ParseStyle, "source type must have one of the enum values");
+ conversion::Result<std::unique_ptr<Source>> source
+ = conversion::convert<std::unique_ptr<Source>>(it->value, id);
+ if (!source) {
+ Log::Warning(Event::ParseStyle, source.error().message);
continue;
}
- const auto type = SourceTypeClass({ typeVal.GetString(), typeVal.GetStringLength() });
-
- // Sources can have URLs, either because they reference an external TileJSON file, or
- // because reference a GeoJSON file. They don't have to have one though when all source
- // parameters are specified inline.
- std::string url;
-
- uint16_t tileSize = util::tileSize;
-
- std::unique_ptr<Tileset> tileset;
- std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> geojsonvt;
-
- switch (type) {
- case SourceType::Raster:
- if (sourceVal.HasMember("tileSize")) {
- const JSValue& tileSizeVal = sourceVal["tileSize"];
- if (tileSizeVal.IsNumber() && tileSizeVal.GetUint64() <= std::numeric_limits<uint16_t>::max()) {
- tileSize = tileSizeVal.GetUint64();
- } else {
- Log::Error(Event::ParseStyle, "invalid tileSize");
- continue;
- }
- }
- // Fall through. Vector sources are forbidden from having a tileSize.
-
- case SourceType::Vector:
- if (sourceVal.HasMember("url")) {
- const JSValue& urlVal = sourceVal["url"];
- if (urlVal.IsString()) {
- url = { urlVal.GetString(), urlVal.GetStringLength() };
- } else {
- Log::Error(Event::ParseStyle, "source url must be a string");
- continue;
- }
- } else {
- tileset = parseTileJSON(sourceVal);
- }
- break;
-
- case SourceType::GeoJSON:
- tileset = std::make_unique<Tileset>();
-
- // We should probably split this up to have URLs in the url property, and actual data
- // in the data property. Until then, we're going to detect the content based on the
- // object type.
- if (sourceVal.HasMember("data")) {
- const JSValue& dataVal = sourceVal["data"];
- if (dataVal.IsString()) {
- // We need to load an external GeoJSON file
- url = { dataVal.GetString(), dataVal.GetStringLength() };
- } else if (dataVal.IsObject()) {
- // We need to parse dataVal as a GeoJSON object
- geojsonvt = parseGeoJSON(dataVal);
- tileset->maxZoom = geojsonvt->options.maxZoom;
- } else {
- Log::Error(Event::ParseStyle, "GeoJSON data must be a URL or an object");
- continue;
- }
- } else {
- Log::Error(Event::ParseStyle, "GeoJSON source must have a data value");
- continue;
- }
-
- break;
-
- default:
- Log::Error(Event::ParseStyle, "source type '%s' is not supported", typeVal.GetString());
- continue;
- }
-
- const std::string id { nameVal.GetString(), nameVal.GetStringLength() };
- std::unique_ptr<Source> source = std::make_unique<Source>(type, id, url, tileSize, std::move(tileset), std::move(geojsonvt));
-
- sourcesMap.emplace(id, source.get());
- sources.emplace_back(std::move(source));
- }
-}
-
-std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> parseGeoJSON(const JSValue& value) {
- using namespace mapbox::geojsonvt;
-
- Options options;
- options.buffer = util::EXTENT / util::tileSize * 128;
- options.extent = util::EXTENT;
-
- try {
- return std::make_unique<GeoJSONVT>(Convert::convert(value, 0), options);
- } catch (const std::exception& ex) {
- Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s", ex.what());
- // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for
- // tiles to load.
- return std::make_unique<GeoJSONVT>(std::vector<ProjectedFeature>{}, options);
- }
-}
-
-std::unique_ptr<Tileset> parseTileJSON(const std::string& json, const std::string& sourceURL, SourceType type, uint16_t tileSize) {
- rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> document;
- document.Parse<0>(json.c_str());
-
- if (document.HasParseError()) {
- std::stringstream message;
- message << document.GetErrorOffset() << " - " << rapidjson::GetParseError_En(document.GetParseError());
- throw std::runtime_error(message.str());
- }
-
- std::unique_ptr<Tileset> result = parseTileJSON(document);
-
- // TODO: Remove this hack by delivering proper URLs in the TileJSON to begin with.
- if (util::mapbox::isMapboxURL(sourceURL)) {
- for (auto& url : result->tiles) {
- url = util::mapbox::canonicalizeTileURL(url, type, tileSize);
- }
+ sourcesMap.emplace(id, (*source).get());
+ sources.emplace_back(std::move(*source));
}
-
- return result;
-}
-
-std::unique_ptr<Tileset> parseTileJSON(const JSValue& value) {
- auto tileset = std::make_unique<Tileset>();
- parseTileJSONMember(value, tileset->tiles, "tiles");
- parseTileJSONMember(value, tileset->minZoom, "minzoom");
- parseTileJSONMember(value, tileset->maxZoom, "maxzoom");
- parseTileJSONMember(value, tileset->attribution, "attribution");
-
- std::array<double, 4> array;
- parseTileJSONMember(value, array, "center");
- tileset->center = { array[0], array[1] };
- tileset->zoom = array[2];
- parseTileJSONMember(value, array, "bounds");
- tileset->bounds = LatLngBounds::hull({ array[0], array[1] }, { array[2], array[3] });
-
- return tileset;
}
void Parser::parseLayers(const JSValue& value) {
@@ -392,275 +179,15 @@ void Parser::parseLayer(const std::string& id, const JSValue& value, std::unique
return;
}
- layer = reference->copy(id, ref);
- layer->baseImpl->parsePaints(value);
+ layer = reference->baseImpl->cloneRef(id);
+ conversion::setPaintProperties(*layer, value);
} else {
- // Otherwise, parse the source/source-layer/filter/render keys to form the bucket.
- if (!value.HasMember("type")) {
- Log::Warning(Event::ParseStyle, "layer '%s' is missing a type", id.c_str());
- return;
- }
-
- const JSValue& typeVal = value["type"];
- if (!typeVal.IsString()) {
- Log::Warning(Event::ParseStyle, "layer '%s' has an invalid type", id.c_str());
+ conversion::Result<std::unique_ptr<Layer>> converted = conversion::convert<std::unique_ptr<Layer>>(value);
+ if (!converted) {
+ Log::Warning(Event::ParseStyle, converted.error().message);
return;
}
-
- std::string type { typeVal.GetString(), typeVal.GetStringLength() };
-
- if (type == "fill") {
- layer = std::make_unique<FillLayer>(id);
- } else if (type == "line") {
- layer = std::make_unique<LineLayer>(id);
- } else if (type == "circle") {
- layer = std::make_unique<CircleLayer>(id);
- } else if (type == "symbol") {
- layer = std::make_unique<SymbolLayer>(id);
- } else if (type == "raster") {
- layer = std::make_unique<RasterLayer>(id);
- } else if (type == "background") {
- layer = std::make_unique<BackgroundLayer>(id);
- } else {
- Log::Warning(Event::ParseStyle, "unknown type '%s' for layer '%s'", type.c_str(), id.c_str());
- return;
- }
-
- Layer::Impl* impl = layer->baseImpl.get();
-
- if (value.HasMember("source")) {
- const JSValue& value_source = value["source"];
- if (value_source.IsString()) {
- impl->source = { value_source.GetString(), value_source.GetStringLength() };
- auto source_it = sourcesMap.find(impl->source);
- if (source_it == sourcesMap.end()) {
- Log::Warning(Event::ParseStyle, "can't find source '%s' required for layer '%s'", impl->source.c_str(), impl->id.c_str());
- }
- } else {
- Log::Warning(Event::ParseStyle, "source of layer '%s' must be a string", impl->id.c_str());
- }
- }
-
- if (value.HasMember("source-layer")) {
- const JSValue& value_source_layer = value["source-layer"];
- if (value_source_layer.IsString()) {
- impl->sourceLayer = { value_source_layer.GetString(), value_source_layer.GetStringLength() };
- } else {
- Log::Warning(Event::ParseStyle, "source-layer of layer '%s' must be a string", impl->id.c_str());
- }
- }
-
- if (value.HasMember("filter")) {
- impl->filter = parseFilter(value["filter"]);
- }
-
- if (value.HasMember("minzoom")) {
- const JSValue& min_zoom = value["minzoom"];
- if (min_zoom.IsNumber()) {
- impl->minZoom = min_zoom.GetDouble();
- } else {
- Log::Warning(Event::ParseStyle, "minzoom of layer %s must be numeric", impl->id.c_str());
- }
- }
-
- if (value.HasMember("maxzoom")) {
- const JSValue& max_zoom = value["maxzoom"];
- if (max_zoom.IsNumber()) {
- impl->maxZoom = max_zoom.GetDouble();
- } else {
- Log::Warning(Event::ParseStyle, "maxzoom of layer %s must be numeric", impl->id.c_str());
- }
- }
-
- if (value.HasMember("layout")) {
- parseVisibility(*layer, value["layout"]);
- impl->parseLayout(value["layout"]);
- }
-
- impl->parsePaints(value);
- }
-}
-
-MBGL_DEFINE_ENUM_CLASS(VisibilityTypeClass, VisibilityType, {
- { VisibilityType::Visible, "visible" },
- { VisibilityType::None, "none" },
-});
-
-void Parser::parseVisibility(Layer& layer, const JSValue& value) {
- Layer::Impl& impl = *layer.baseImpl;
- if (!value.HasMember("visibility")) {
- return;
- } else if (!value["visibility"].IsString()) {
- Log::Warning(Event::ParseStyle, "value of 'visibility' must be a string");
- impl.visibility = VisibilityType::Visible;
- return;
- }
- impl.visibility = VisibilityTypeClass({ value["visibility"].GetString(), value["visibility"].GetStringLength() });
-}
-
-Value parseFeatureType(const Value& value) {
- if (value == std::string("Point")) {
- return Value(uint64_t(FeatureType::Point));
- } else if (value == std::string("LineString")) {
- return Value(uint64_t(FeatureType::LineString));
- } else if (value == std::string("Polygon")) {
- return Value(uint64_t(FeatureType::Polygon));
- } else {
- Log::Warning(Event::ParseStyle, "value for $type filter must be Point, LineString, or Polygon");
- return Value(uint64_t(FeatureType::Unknown));
- }
-}
-
-Value parseValue(const JSValue& 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;
- }
-}
-
-template <class Expression>
-Filter parseUnaryFilter(const JSValue& value) {
- Filter empty;
-
- if (value.Size() < 2) {
- Log::Warning(Event::ParseStyle, "filter expression must have 2 elements");
- return empty;
- }
-
- if (!value[1u].IsString()) {
- Log::Warning(Event::ParseStyle, "filter expression key must be a string");
- return empty;
- }
-
- Expression expression;
- expression.key = { value[1u].GetString(), value[1u].GetStringLength() };
- return expression;
-}
-
-template <class Expression>
-Filter parseBinaryFilter(const JSValue& value) {
- Filter empty;
-
- if (value.Size() < 3) {
- Log::Warning(Event::ParseStyle, "filter expression must have 3 elements");
- return empty;
- }
-
- if (!value[1u].IsString()) {
- Log::Warning(Event::ParseStyle, "filter expression key must be a string");
- return empty;
- }
-
- Expression expression;
- expression.key = { value[1u].GetString(), value[1u].GetStringLength() };
- expression.value = parseValue(value[2u]);
-
- if (expression.key == "$type") {
- expression.value = parseFeatureType(expression.value);
- }
-
- return expression;
-}
-
-template <class Expression>
-Filter parseSetFilter(const JSValue& value) {
- Filter empty;
-
- if (value.Size() < 2) {
- Log::Warning(Event::ParseStyle, "filter expression must at least 2 elements");
- return empty;
- }
-
- if (!value[1u].IsString()) {
- Log::Warning(Event::ParseStyle, "filter expression key must be a string");
- return empty;
- }
-
- Expression expression;
- expression.key = { value[1u].GetString(), value[1u].GetStringLength() };
- for (rapidjson::SizeType i = 2; i < value.Size(); ++i) {
- Value parsedValue = parseValue(value[i]);
- if (expression.key == "$type") {
- parsedValue = parseFeatureType(parsedValue);
- }
- expression.values.push_back(parsedValue);
- }
- return expression;
-}
-
-template <class Expression>
-Filter parseCompoundFilter(const JSValue& value) {
- Expression expression;
- for (rapidjson::SizeType i = 1; i < value.Size(); ++i) {
- expression.filters.push_back(parseFilter(value[i]));
- }
- return expression;
-}
-
-Filter parseFilter(const JSValue& value) {
- Filter empty;
-
- if (!value.IsArray()) {
- Log::Warning(Event::ParseStyle, "filter expression must be an array");
- return empty;
- }
-
- if (value.Size() < 1) {
- Log::Warning(Event::ParseStyle, "filter expression must have at least 1 element");
- return empty;
- }
-
- if (!value[0u].IsString()) {
- Log::Warning(Event::ParseStyle, "filter operator must be a string");
- return empty;
- }
-
- std::string op = { value[0u].GetString(), value[0u].GetStringLength() };
-
- if (op == "==") {
- return parseBinaryFilter<EqualsFilter>(value);
- } else if (op == "!=") {
- return parseBinaryFilter<NotEqualsFilter>(value);
- } else if (op == ">") {
- return parseBinaryFilter<GreaterThanFilter>(value);
- } else if (op == ">=") {
- return parseBinaryFilter<GreaterThanEqualsFilter>(value);
- } else if (op == "<") {
- return parseBinaryFilter<LessThanFilter>(value);
- } else if (op == "<=") {
- return parseBinaryFilter<LessThanEqualsFilter>(value);
- } else if (op == "in") {
- return parseSetFilter<InFilter>(value);
- } else if (op == "!in") {
- return parseSetFilter<NotInFilter>(value);
- } else if (op == "all") {
- return parseCompoundFilter<AllFilter>(value);
- } else if (op == "any") {
- return parseCompoundFilter<AnyFilter>(value);
- } else if (op == "none") {
- return parseCompoundFilter<NoneFilter>(value);
- } else if (op == "has") {
- return parseUnaryFilter<HasFilter>(value);
- } else if (op == "!has") {
- return parseUnaryFilter<NotHasFilter>(value);
- } else {
- Log::Warning(Event::ParseStyle, "filter operator must be one of \"==\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"in\", \"!in\", \"all\", \"any\", \"none\", \"has\", or \"!has\"");
- return empty;
+ layer = std::move(*converted);
}
}
diff --git a/src/mbgl/style/parser.hpp b/src/mbgl/style/parser.hpp
index ea821fabde..faf80cee93 100644
--- a/src/mbgl/style/parser.hpp
+++ b/src/mbgl/style/parser.hpp
@@ -2,7 +2,6 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/source.hpp>
-#include <mbgl/style/filter.hpp>
#include <mbgl/util/rapidjson.hpp>
#include <mbgl/util/font_stack.hpp>
@@ -16,13 +15,6 @@
namespace mbgl {
namespace style {
-std::unique_ptr<Tileset> parseTileJSON(const std::string& json, const std::string& sourceURL, SourceType, uint16_t tileSize);
-std::unique_ptr<Tileset> parseTileJSON(const JSValue&);
-
-std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> parseGeoJSON(const JSValue&);
-
-Filter parseFilter(const JSValue&);
-
class Parser {
public:
~Parser();
@@ -42,7 +34,6 @@ private:
void parseSources(const JSValue&);
void parseLayers(const JSValue&);
void parseLayer(const std::string& id, const JSValue&, std::unique_ptr<Layer>&);
- void parseVisibility(Layer&, const JSValue& value);
std::unordered_map<std::string, const Source*> sourcesMap;
std::unordered_map<std::string, std::pair<const JSValue&, std::unique_ptr<Layer>>> layersMap;
diff --git a/src/mbgl/style/property_evaluator.cpp b/src/mbgl/style/property_evaluator.cpp
index d2e633c782..abb3681efa 100644
--- a/src/mbgl/style/property_evaluator.cpp
+++ b/src/mbgl/style/property_evaluator.cpp
@@ -11,25 +11,28 @@ namespace mbgl {
namespace style {
template <typename T>
-inline T defaultStopsValue();
-
-template <> inline bool defaultStopsValue() { return true; }
-template <> inline float defaultStopsValue() { return 1.0f; }
-template <> inline Color defaultStopsValue() { return {{ 0, 0, 0, 1 }}; }
-template <> inline std::vector<float> defaultStopsValue() { return {{ 1, 0 }}; }
-template <> inline std::vector<std::string> defaultStopsValue() { return {{}}; }
-template <> inline std::array<float, 2> defaultStopsValue() { return {{ 0, 0 }}; }
-
-template <> inline std::string defaultStopsValue() { return {}; }
-template <> inline TranslateAnchorType defaultStopsValue() { return {}; };
-template <> inline RotateAnchorType defaultStopsValue() { return {}; };
-template <> inline LineCapType defaultStopsValue() { return {}; };
-template <> inline LineJoinType defaultStopsValue() { return {}; };
-template <> inline SymbolPlacementType defaultStopsValue() { return {}; };
-template <> inline TextAnchorType defaultStopsValue() { return {}; };
-template <> inline TextJustifyType defaultStopsValue() { return {}; };
-template <> inline TextTransformType defaultStopsValue() { return {}; };
-template <> inline RotationAlignmentType defaultStopsValue() { return {}; };
+T defaultStopsValue();
+
+template <> bool defaultStopsValue() { return true; }
+template <> float defaultStopsValue() { return 1.0f; }
+template <> Color defaultStopsValue() { return { 0, 0, 0, 1 }; }
+template <> std::vector<float> defaultStopsValue() { return {{ 1, 0 }}; }
+template <> std::vector<std::string> defaultStopsValue() { return {{}}; }
+template <> std::array<float, 2> defaultStopsValue() { return {{ 0, 0 }}; }
+template <> std::array<float, 4> defaultStopsValue() { return {{ 0, 0, 0, 0 }}; }
+
+template <> std::string defaultStopsValue() { return {}; }
+template <> TranslateAnchorType defaultStopsValue() { return {}; }
+template <> RotateAnchorType defaultStopsValue() { return {}; }
+template <> CirclePitchScaleType defaultStopsValue() { return {}; }
+template <> LineCapType defaultStopsValue() { return {}; }
+template <> LineJoinType defaultStopsValue() { return {}; }
+template <> SymbolPlacementType defaultStopsValue() { return {}; }
+template <> TextAnchorType defaultStopsValue() { return {}; }
+template <> TextJustifyType defaultStopsValue() { return {}; }
+template <> TextTransformType defaultStopsValue() { return {}; }
+template <> AlignmentType defaultStopsValue() { return {}; }
+template <> IconTextFitType defaultStopsValue() { return {}; };
template <typename T>
T PropertyEvaluator<T>::operator()(const Function<T>& fn) const {
@@ -87,17 +90,20 @@ template class PropertyEvaluator<Color>;
template class PropertyEvaluator<std::vector<float>>;
template class PropertyEvaluator<std::vector<std::string>>;
template class PropertyEvaluator<std::array<float, 2>>;
+template class PropertyEvaluator<std::array<float, 4>>;
template class PropertyEvaluator<std::string>;
template class PropertyEvaluator<TranslateAnchorType>;
template class PropertyEvaluator<RotateAnchorType>;
+template class PropertyEvaluator<CirclePitchScaleType>;
template class PropertyEvaluator<LineCapType>;
template class PropertyEvaluator<LineJoinType>;
template class PropertyEvaluator<SymbolPlacementType>;
template class PropertyEvaluator<TextAnchorType>;
template class PropertyEvaluator<TextJustifyType>;
template class PropertyEvaluator<TextTransformType>;
-template class PropertyEvaluator<RotationAlignmentType>;
+template class PropertyEvaluator<AlignmentType>;
+template class PropertyEvaluator<IconTextFitType>;
template <typename T>
Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const Undefined&) const {
@@ -110,7 +116,7 @@ Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const T& constant) const {
}
template <typename T>
-inline T getBiggestStopLessThan(const Function<T>& function, float z) {
+T getBiggestStopLessThan(const Function<T>& function, float z) {
const auto& stops = function.getStops();
for (uint32_t i = 0; i < stops.size(); i++) {
if (stops[i].first > z) {
diff --git a/src/mbgl/style/property_evaluator.hpp b/src/mbgl/style/property_evaluator.hpp
index 77100bda46..a0bce2f499 100644
--- a/src/mbgl/style/property_evaluator.hpp
+++ b/src/mbgl/style/property_evaluator.hpp
@@ -13,9 +13,9 @@ class PropertyEvaluator {
public:
using ResultType = T;
- PropertyEvaluator(const CalculationParameters& parameters_, const T& defaultValue_)
+ PropertyEvaluator(const CalculationParameters& parameters_, T defaultValue_)
: parameters(parameters_),
- defaultValue(defaultValue_) {}
+ defaultValue(std::move(defaultValue_)) {}
T operator()(const Undefined&) const { return defaultValue; }
T operator()(const T& constant) const { return constant; }
@@ -40,9 +40,9 @@ class CrossFadedPropertyEvaluator {
public:
using ResultType = Faded<T>;
- CrossFadedPropertyEvaluator(const CalculationParameters& parameters_, const T& defaultValue_)
+ CrossFadedPropertyEvaluator(const CalculationParameters& parameters_, T defaultValue_)
: parameters(parameters_),
- defaultValue(defaultValue_) {}
+ defaultValue(std::move(defaultValue_)) {}
Faded<T> operator()(const Undefined&) const;
Faded<T> operator()(const T& constant) const;
@@ -61,6 +61,6 @@ namespace util {
template <typename T>
struct Interpolator<style::Faded<T>>
: Uninterpolated {};
-}
+} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/style/property_parsing.cpp b/src/mbgl/style/property_parsing.cpp
index 9f60ddf3b6..16ce0f4adc 100644
--- a/src/mbgl/style/property_parsing.cpp
+++ b/src/mbgl/style/property_parsing.cpp
@@ -1,269 +1,8 @@
#include <mbgl/style/property_parsing.hpp>
-#include <mbgl/platform/log.hpp>
-
-#include <csscolorparser/csscolorparser.hpp>
-
namespace mbgl {
namespace style {
-template <>
-optional<bool> parseConstant(const char* name, const JSValue& value) {
- if (!value.IsBool()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a boolean", name);
- return {};
- }
-
- return value.GetBool();
-}
-
-template <>
-optional<float> parseConstant(const char* name, const JSValue& value) {
- if (!value.IsNumber()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a number, or a number function", name);
- return {};
- }
-
- return value.GetDouble();
-}
-
-template <>
-optional<std::string> parseConstant(const char* name, const JSValue& value) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
- return {};
- }
-
- return std::string { value.GetString(), value.GetStringLength() };
-}
-
-template <>
-optional<Color> parseConstant(const char* name, const JSValue& value) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
- return {};
- }
-
- CSSColorParser::Color css_color = CSSColorParser::parse({ value.GetString(), value.GetStringLength() });
-
- // Premultiply the color.
- const float factor = css_color.a / 255;
-
- return Color{{(float)css_color.r * factor,
- (float)css_color.g * factor,
- (float)css_color.b * factor,
- css_color.a}};
-}
-
-MBGL_DEFINE_ENUM_CLASS(TranslateAnchorTypeClass, TranslateAnchorType, {
- { TranslateAnchorType::Map, "map" },
- { TranslateAnchorType::Viewport, "viewport" },
-});
-
-template <>
-optional<TranslateAnchorType> parseConstant(const char* name, const JSValue& value) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
- return {};
- }
-
- return { TranslateAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-MBGL_DEFINE_ENUM_CLASS(RotateAnchorTypeClass, RotateAnchorType, {
- { RotateAnchorType::Map, "map" },
- { RotateAnchorType::Viewport, "viewport" },
-});
-
-template <>
-optional<RotateAnchorType> parseConstant<RotateAnchorType>(const char* name, const JSValue& value) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
- return {};
- }
-
- return { RotateAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-MBGL_DEFINE_ENUM_CLASS(LineCapTypeClass, LineCapType, {
- { LineCapType::Round, "round" },
- { LineCapType::Butt, "butt" },
- { LineCapType::Square, "square" },
-});
-
-template <>
-optional<LineCapType> parseConstant<LineCapType>(const char* name, const JSValue& value) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
- return {};
- }
-
- return { LineCapTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-MBGL_DEFINE_ENUM_CLASS(LineJoinTypeClass, LineJoinType, {
- { LineJoinType::Miter, "miter" },
- { LineJoinType::Bevel, "bevel" },
- { LineJoinType::Round, "round" },
- { LineJoinType::FakeRound, "fakeround" },
- { LineJoinType::FlipBevel, "flipbevel" },
-});
-
-template <>
-optional<LineJoinType> parseConstant<LineJoinType>(const char* name, const JSValue& value) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
- return {};
- }
-
- return { LineJoinTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-MBGL_DEFINE_ENUM_CLASS(SymbolPlacementTypeClass, SymbolPlacementType, {
- { SymbolPlacementType::Point, "point" },
- { SymbolPlacementType::Line, "line" },
-});
-
-template <>
-optional<SymbolPlacementType> parseConstant<SymbolPlacementType>(const char* name, const JSValue& value) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
- return {};
- }
-
- return { SymbolPlacementTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-MBGL_DEFINE_ENUM_CLASS(TextAnchorTypeClass, TextAnchorType, {
- { TextAnchorType::Center, "center" },
- { TextAnchorType::Left, "left" },
- { TextAnchorType::Right, "right" },
- { TextAnchorType::Top, "top" },
- { TextAnchorType::Bottom, "bottom" },
- { TextAnchorType::TopLeft, "top-left" },
- { TextAnchorType::TopRight, "top-right" },
- { TextAnchorType::BottomLeft, "bottom-left" },
- { TextAnchorType::BottomRight, "bottom-right" }
-});
-
-template <>
-optional<TextAnchorType> parseConstant<TextAnchorType>(const char* name, const JSValue& value) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
- return {};
- }
-
- return { TextAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-MBGL_DEFINE_ENUM_CLASS(TextJustifyTypeClass, TextJustifyType, {
- { TextJustifyType::Center, "center" },
- { TextJustifyType::Left, "left" },
- { TextJustifyType::Right, "right" },
-});
-
-template <>
-optional<TextJustifyType> parseConstant<TextJustifyType>(const char* name, const JSValue& value) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
- return {};
- }
-
- return { TextJustifyTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-MBGL_DEFINE_ENUM_CLASS(TextTransformTypeClass, TextTransformType, {
- { TextTransformType::None, "none" },
- { TextTransformType::Uppercase, "uppercase" },
- { TextTransformType::Lowercase, "lowercase" },
-});
-
-template <>
-optional<TextTransformType> parseConstant<TextTransformType>(const char* name, const JSValue& value) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
- return {};
- }
-
- return { TextTransformTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-MBGL_DEFINE_ENUM_CLASS(RotationAlignmentTypeClass, RotationAlignmentType, {
- { RotationAlignmentType::Map, "map" },
- { RotationAlignmentType::Viewport, "viewport" },
-});
-
-template <>
-optional<RotationAlignmentType> parseConstant<RotationAlignmentType>(const char* name, const JSValue& value) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
- return {};
- }
-
- return { RotationAlignmentTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-template <>
-optional<std::array<float, 2>> parseConstant(const char* name, const JSValue& value) {
- if (value.IsArray() && value.Size() == 2 &&
- value[rapidjson::SizeType(0)].IsNumber() &&
- value[rapidjson::SizeType(1)].IsNumber()) {
-
- float first = value[rapidjson::SizeType(0)].GetDouble();
- float second = value[rapidjson::SizeType(1)].GetDouble();
- return { {{ first, second }} };
- } else {
- Log::Warning(Event::ParseStyle, "value of '%s' must be an array of two numbers", name);
- return {};
- }
-}
-
-template <>
-optional<std::vector<float>> parseConstant(const char* name, const JSValue& value) {
- if (!value.IsArray()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be an array of numbers", name);
- return {};
- }
-
- std::vector<float> result;
-
- for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
- const JSValue& part = value[i];
-
- if (!part.IsNumber()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be an array of numbers", name);
- return {};
- }
-
- result.push_back(part.GetDouble());
- }
-
- return result;
-}
-
-template <>
-optional<std::vector<std::string>> parseConstant(const char* name, const JSValue& value) {
- if (!value.IsArray()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be an array of strings", name);
- return {};
- }
-
- std::vector<std::string> result;
-
- for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
- const JSValue& part = value[i];
-
- if (!part.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be an array of strings", name);
- return {};
- }
-
- result.push_back({ part.GetString(), part.GetStringLength() });
- }
-
- return result;
-}
-
optional<TransitionOptions> parseTransitionOptions(const char *, const JSValue& value) {
if (!value.IsObject()) {
return {};
@@ -283,7 +22,7 @@ optional<TransitionOptions> parseTransitionOptions(const char *, const JSValue&
return {};
}
- return TransitionOptions(duration, delay);
+ return TransitionOptions { duration, delay };
}
} // namespace style
diff --git a/src/mbgl/style/property_parsing.hpp b/src/mbgl/style/property_parsing.hpp
index bb894c2407..8c2bd2c0f4 100644
--- a/src/mbgl/style/property_parsing.hpp
+++ b/src/mbgl/style/property_parsing.hpp
@@ -1,109 +1,23 @@
#pragma once
-#include <mbgl/style/types.hpp>
#include <mbgl/style/property_value.hpp>
#include <mbgl/style/transition_options.hpp>
-
-#include <mbgl/util/rapidjson.hpp>
-#include <mbgl/util/optional.hpp>
-#include <mbgl/util/color.hpp>
+#include <mbgl/style/rapidjson_conversion.hpp>
+#include <mbgl/style/conversion/property_value.hpp>
#include <mbgl/platform/log.hpp>
-#include <string>
-#include <array>
-#include <vector>
-
namespace mbgl {
namespace style {
template <typename T>
-optional<T> parseConstant(const char* name, const JSValue&);
-
-template <> optional<bool> parseConstant(const char*, const JSValue&);
-template <> optional<float> parseConstant(const char*, const JSValue&);
-template <> optional<std::string> parseConstant(const char*, const JSValue&);
-template <> optional<Color> parseConstant(const char*, const JSValue&);
-template <> optional<TranslateAnchorType> parseConstant(const char*, const JSValue&);
-template <> optional<RotateAnchorType> parseConstant(const char*, const JSValue&);
-template <> optional<LineCapType> parseConstant(const char*, const JSValue&);
-template <> optional<LineJoinType> parseConstant(const char*, const JSValue&);
-template <> optional<SymbolPlacementType> parseConstant(const char*, const JSValue&);
-template <> optional<TextAnchorType> parseConstant(const char*, const JSValue&);
-template <> optional<TextJustifyType> parseConstant(const char*, const JSValue&);
-template <> optional<TextTransformType> parseConstant(const char*, const JSValue&);
-template <> optional<RotationAlignmentType> parseConstant(const char*, const JSValue&);
-template <> optional<std::array<float, 2>> parseConstant(const char*, const JSValue&);
-template <> optional<std::vector<float>> parseConstant(const char*, const JSValue&);
-template <> optional<std::vector<std::string>> parseConstant(const char*, const JSValue&);
-
-template <typename T>
PropertyValue<T> parseProperty(const char* name, const JSValue& value) {
- if (!value.IsObject()) {
- auto constant = parseConstant<T>(name, value);
-
- if (!constant) {
- return {};
- }
-
- return *constant;
- }
-
- if (!value.HasMember("stops")) {
- Log::Warning(Event::ParseStyle, "function must specify a function type");
+ conversion::Result<PropertyValue<T>> result = conversion::convert<PropertyValue<T>>(value);
+ if (!result) {
+ Log::Warning(Event::ParseStyle, "%s: %s", name, result.error().message);
return {};
}
-
- float base = 1.0f;
-
- if (value.HasMember("base")) {
- const JSValue& value_base = value["base"];
-
- if (!value_base.IsNumber()) {
- Log::Warning(Event::ParseStyle, "base must be numeric");
- return {};
- }
-
- base = value_base.GetDouble();
- }
-
- const JSValue& stopsValue = value["stops"];
-
- if (!stopsValue.IsArray()) {
- Log::Warning(Event::ParseStyle, "stops function must specify a stops array");
- return {};
- }
-
- std::vector<std::pair<float, T>> stops;
-
- for (rapidjson::SizeType i = 0; i < stopsValue.Size(); ++i) {
- const JSValue& stop = stopsValue[i];
-
- if (!stop.IsArray()) {
- Log::Warning(Event::ParseStyle, "function argument must be a numeric value");
- return {};
- }
-
- if (stop.Size() != 2) {
- Log::Warning(Event::ParseStyle, "stop must have zoom level and value specification");
- return {};
- }
-
- const JSValue& z = stop[rapidjson::SizeType(0)];
- if (!z.IsNumber()) {
- Log::Warning(Event::ParseStyle, "zoom level in stop must be a number");
- return {};
- }
-
- optional<T> v = parseConstant<T>(name, stop[rapidjson::SizeType(1)]);
- if (!v) {
- return {};
- }
-
- stops.emplace_back(z.GetDouble(), *v);
- }
-
- return Function<T>(stops, base);
+ return *result;
}
optional<TransitionOptions> parseTransitionOptions(const char * name, const JSValue&);
diff --git a/src/mbgl/style/rapidjson_conversion.hpp b/src/mbgl/style/rapidjson_conversion.hpp
new file mode 100644
index 0000000000..ecf044fb64
--- /dev/null
+++ b/src/mbgl/style/rapidjson_conversion.hpp
@@ -0,0 +1,94 @@
+#pragma once
+
+#include <mbgl/util/rapidjson.hpp>
+#include <mbgl/util/feature.hpp>
+#include <mbgl/style/conversion.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+inline bool isUndefined(const JSValue& value) {
+ return value.IsNull();
+}
+
+inline bool isArray(const JSValue& value) {
+ return value.IsArray();
+}
+
+inline std::size_t arrayLength(const JSValue& value) {
+ return value.Size();
+}
+
+inline const JSValue& arrayMember(const JSValue& value, std::size_t i) {
+ return value[rapidjson::SizeType(i)];
+}
+
+inline bool isObject(const JSValue& value) {
+ return value.IsObject();
+}
+
+inline const JSValue* objectMember(const JSValue& value, const char * name) {
+ if (!value.HasMember(name)) {
+ return nullptr;
+ }
+ return &value[name];
+}
+
+template <class Fn>
+optional<Error> eachMember(const JSValue& value, Fn&& fn) {
+ for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it) {
+ optional<Error> result = fn({it->name.GetString(), it->name.GetStringLength()}, it->value);
+ if (result) {
+ return result;
+ }
+ }
+ return {};
+}
+
+inline optional<bool> toBool(const JSValue& value) {
+ if (!value.IsBool()) {
+ return {};
+ }
+ return value.GetBool();
+}
+
+inline optional<float> toNumber(const JSValue& value) {
+ if (!value.IsNumber()) {
+ return {};
+ }
+ return value.GetDouble();
+}
+
+inline optional<std::string> toString(const JSValue& value) {
+ if (!value.IsString()) {
+ return {};
+ }
+ return {{ value.GetString(), value.GetStringLength() }};
+}
+
+inline optional<Value> toValue(const JSValue& 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 {};
+ }
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/source.cpp b/src/mbgl/style/source.cpp
index 8e5973f412..4c83a3ce0e 100644
--- a/src/mbgl/style/source.cpp
+++ b/src/mbgl/style/source.cpp
@@ -1,427 +1,17 @@
#include <mbgl/style/source.hpp>
-#include <mbgl/style/source_observer.hpp>
-#include <mbgl/map/transform.hpp>
-#include <mbgl/tile/tile.hpp>
-#include <mbgl/tile/vector_tile.hpp>
-#include <mbgl/annotation/annotation_tile.hpp>
-#include <mbgl/tile/geojson_tile.hpp>
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/util/exception.hpp>
-#include <mbgl/util/constants.hpp>
-#include <mbgl/storage/resource.hpp>
-#include <mbgl/storage/response.hpp>
-#include <mbgl/storage/file_source.hpp>
-#include <mbgl/style/layer.hpp>
-#include <mbgl/style/update_parameters.hpp>
-#include <mbgl/style/query_parameters.hpp>
-#include <mbgl/platform/log.hpp>
-#include <mbgl/math/minmax.hpp>
-#include <mbgl/math/clamp.hpp>
-#include <mbgl/util/std.hpp>
-#include <mbgl/util/token.hpp>
-#include <mbgl/util/string.hpp>
-#include <mbgl/util/tile_cover.hpp>
-
-#include <mbgl/tile/vector_tile_data.hpp>
-#include <mbgl/tile/raster_tile_data.hpp>
-#include <mbgl/style/parser.hpp>
-#include <mbgl/gl/debugging.hpp>
-
-#include <mbgl/algorithm/update_renderables.hpp>
-
-#include <mapbox/geojsonvt.hpp>
-#include <mapbox/geojsonvt/convert.hpp>
-#include <mapbox/geometry/envelope.hpp>
-
-#include <rapidjson/error/en.h>
-
-#include <algorithm>
-#include <sstream>
+#include <mbgl/style/source_impl.hpp>
namespace mbgl {
namespace style {
-static SourceObserver nullObserver;
-
-Source::Source(SourceType type_,
- const std::string& id_,
- const std::string& url_,
- uint16_t tileSize_,
- std::unique_ptr<Tileset>&& tileset_,
- std::unique_ptr<mapbox::geojsonvt::GeoJSONVT>&& geojsonvt_)
- : type(type_),
- id(id_),
- url(url_),
- tileSize(tileSize_),
- tileset(std::move(tileset_)),
- geojsonvt(std::move(geojsonvt_)),
- observer(&nullObserver) {
+Source::Source(SourceType type_, std::unique_ptr<Impl> baseImpl_)
+ : baseImpl(std::move(baseImpl_)), type(type_) {
}
Source::~Source() = default;
-bool Source::isLoaded() const {
- if (!loaded) return false;
-
- for (const auto& pair : tileDataMap) {
- if (!pair.second->isComplete()) {
- return false;
- }
- }
-
- return true;
-}
-
-bool Source::isLoading() const {
- return !loaded && req.operator bool();
-}
-
-void Source::load(FileSource& fileSource) {
- if (url.empty()) {
- // In case there is no URL set, we assume that we already have all of the data because the
- // TileJSON was specified inline in the stylesheet.
- loaded = true;
- return;
- }
-
- if (req) {
- // We don't have a Tileset object yet, but there's already a request underway to load
- // the data.
- return;
- }
-
- // URL may either be a TileJSON file, or a GeoJSON file.
- req = fileSource.request(Resource::source(url), [this](Response res) {
- if (res.error) {
- observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(res.error->message)));
- } else if (res.notModified) {
- return;
- } else if (res.noContent) {
- observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty source")));
- } else {
- bool reloadTiles = false;
-
- if (type == SourceType::Vector || type == SourceType::Raster) {
- std::unique_ptr<Tileset> newTileset;
-
- // Create a new copy of the Tileset object that holds the base values we've parsed
- // from the stylesheet. Then merge in the values parsed from the TileJSON we retrieved
- // via the URL.
- try {
- newTileset = style::parseTileJSON(*res.data, url, type, tileSize);
- } catch (...) {
- observer->onSourceError(*this, std::current_exception());
- return;
- }
-
- // Check whether previous information specifies different tile
- if (tileset && tileset->tiles != newTileset->tiles) {
- reloadTiles = true;
-
- // Tile size changed: We need to recalculate the tiles we need to load because we
- // might have to load tiles for a different zoom level
- // This is done automatically when we trigger the onSourceLoaded observer below.
-
- // Min/Max zoom changed: We need to recalculate what tiles to load, if we have tiles
- // loaded that are outside the new zoom range
- // This is done automatically when we trigger the onSourceLoaded observer below.
-
- // Attribution changed: We need to notify the embedding application that this
- // changed. See https://github.com/mapbox/mapbox-gl-native/issues/2723
- // This is not yet implemented.
-
- // Center/bounds changed: We're not using these values currently
- }
-
- tileset = std::move(newTileset);
- } else if (type == SourceType::GeoJSON) {
- std::unique_ptr<Tileset> newTileset = std::make_unique<Tileset>();
-
- rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> d;
- d.Parse<0>(res.data->c_str());
-
- if (d.HasParseError()) {
- std::stringstream message;
- message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError());
- observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(message.str())));
- return;
- }
-
- geojsonvt = style::parseGeoJSON(d);
- reloadTiles = true;
-
- newTileset->maxZoom = geojsonvt->options.maxZoom;
- tileset = std::move(newTileset);
- }
-
- if (reloadTiles) {
- // Tile information changed because we got new GeoJSON data, or a new tile URL.
- tileDataMap.clear();
- tiles.clear();
- cache.clear();
- }
-
- loaded = true;
- observer->onSourceLoaded(*this);
- }
- });
-}
-
-void Source::updateMatrices(const mat4 &projMatrix, const TransformState &transform) {
- for (auto& pair : tiles) {
- auto& tile = pair.second;
- transform.matrixFor(tile.matrix, tile.id);
- matrix::multiply(tile.matrix, projMatrix, tile.matrix);
- }
-}
-
-void Source::finishRender(Painter &painter) {
- for (auto& pair : tiles) {
- auto& tile = pair.second;
- painter.renderTileDebug(tile);
- }
-}
-
-const std::map<UnwrappedTileID, Tile>& Source::getTiles() const {
- return tiles;
-}
-
-std::unique_ptr<TileData> Source::createTile(const OverscaledTileID& overscaledTileID,
- const UpdateParameters& parameters) {
- std::unique_ptr<TileData> data = cache.get(overscaledTileID);
- if (data) {
- return data;
- }
-
- auto callback = std::bind(&Source::tileLoadingCallback, this, overscaledTileID,
- std::placeholders::_1, true);
-
- // If we don't find working tile data, we're just going to load it.
- if (type == SourceType::Raster) {
- data = std::make_unique<RasterTileData>(overscaledTileID, parameters.pixelRatio,
- tileset->tiles.at(0), parameters.texturePool,
- parameters.worker, parameters.fileSource, callback);
- } else {
- std::unique_ptr<GeometryTileMonitor> monitor;
-
- if (type == SourceType::Vector) {
- monitor = std::make_unique<VectorTileMonitor>(overscaledTileID, parameters.pixelRatio, tileset->tiles.at(0), parameters.fileSource);
- } else if (type == SourceType::Annotations) {
- monitor = std::make_unique<AnnotationTileMonitor>(overscaledTileID, parameters.annotationManager);
- } else if (type == SourceType::GeoJSON) {
- monitor = std::make_unique<GeoJSONTileMonitor>(geojsonvt.get(), overscaledTileID);
- } else {
- Log::Warning(Event::Style, "Source type '%s' is not implemented", SourceTypeClass(type).c_str());
- return nullptr;
- }
-
- data = std::make_unique<VectorTileData>(overscaledTileID, std::move(monitor), id,
- parameters.style, parameters.mode, callback);
- }
-
- return data;
-}
-
-TileData* Source::getTileData(const OverscaledTileID& overscaledTileID) const {
- auto it = tileDataMap.find(overscaledTileID);
- if (it != tileDataMap.end()) {
- return it->second.get();
- } else {
- return nullptr;
- }
-}
-
-bool Source::update(const UpdateParameters& parameters) {
- bool allTilesUpdated = true;
-
- if (!loaded || parameters.animationTime <= updated) {
- return allTilesUpdated;
- }
-
- // Determine the overzooming/underzooming amounts and required tiles.
- int32_t overscaledZoom = util::coveringZoomLevel(parameters.transformState.getZoom(), type, tileSize);
- int32_t dataTileZoom = overscaledZoom;
-
- std::vector<UnwrappedTileID> idealTiles;
- if (overscaledZoom >= tileset->minZoom) {
- int32_t idealZoom = std::min<int32_t>(tileset->maxZoom, overscaledZoom);
-
- // Make sure we're not reparsing overzoomed raster tiles.
- if (type == SourceType::Raster) {
- dataTileZoom = idealZoom;
- }
-
- idealTiles = util::tileCover(parameters.transformState, idealZoom);
- }
-
- // Stores a list of all the data tiles that we're definitely going to retain. There are two
- // kinds of tiles we need: the ideal tiles determined by the tile cover. They may not yet be in
- // use because they're still loading. In addition to that, we also need to retain all tiles that
- // we're actively using, e.g. as a replacement for tile that aren't loaded yet.
- std::set<OverscaledTileID> retain;
-
- auto retainTileDataFn = [&retain](const TileData& tileData) -> void {
- retain.emplace(tileData.id);
- };
- auto getTileDataFn = [this](const OverscaledTileID& dataTileID) -> TileData* {
- return getTileData(dataTileID);
- };
- auto createTileDataFn = [this, &parameters](const OverscaledTileID& dataTileID) -> TileData* {
- if (auto data = createTile(dataTileID, parameters)) {
- return tileDataMap.emplace(dataTileID, std::move(data)).first->second.get();
- } else {
- return nullptr;
- }
- };
- auto renderTileFn = [this](const UnwrappedTileID& renderTileID, TileData& tileData) {
- tiles.emplace(renderTileID, Tile{ renderTileID, tileData });
- };
-
- tiles.clear();
- algorithm::updateRenderables(getTileDataFn, createTileDataFn, retainTileDataFn, renderTileFn,
- idealTiles, *tileset, dataTileZoom);
-
- if (type != SourceType::Raster && type != SourceType::Annotations && cache.getSize() == 0) {
- size_t conservativeCacheSize =
- ((float)parameters.transformState.getWidth() / util::tileSize) *
- ((float)parameters.transformState.getHeight() / util::tileSize) *
- (parameters.transformState.getMaxZoom() - parameters.transformState.getMinZoom() + 1) *
- 0.5;
- cache.setSize(conservativeCacheSize);
- }
-
- // Remove stale data tiles from the active set of tiles.
- // This goes through the (sorted!) tileDataMap and retain set in lockstep and removes items from
- // tileDataMap that don't have the corresponding key in the retain set.
- auto dataIt = tileDataMap.begin();
- auto retainIt = retain.begin();
- while (dataIt != tileDataMap.end()) {
- if (retainIt == retain.end() || dataIt->first < *retainIt) {
- cache.add(dataIt->first, std::move(dataIt->second));
- tileDataMap.erase(dataIt++);
- } else {
- if (!(*retainIt < dataIt->first)) {
- ++dataIt;
- }
- ++retainIt;
- }
- }
-
- for (auto& pair : tileDataMap) {
- const auto& dataTileID = pair.first;
- auto tileData = pair.second.get();
- if (parameters.shouldReparsePartialTiles && tileData->isIncomplete()) {
- auto callback = std::bind(&Source::tileLoadingCallback, this, dataTileID,
- std::placeholders::_1, false);
-
- if (!tileData->parsePending(callback)) {
- allTilesUpdated = false;
- }
- } else {
- tileData->redoPlacement({ parameters.transformState.getAngle(),
- parameters.transformState.getPitch(),
- parameters.debugOptions & MapDebugOptions::Collision },
- [this]() { observer->onPlacementRedone(); });
- }
- }
-
- updated = parameters.animationTime;
-
- return allTilesUpdated;
-}
-
-static Point<int16_t> coordinateToTilePoint(const UnwrappedTileID& tileID, const Point<double>& p) {
- auto zoomedCoord = TileCoordinate { p, 0 }.zoomTo(tileID.canonical.z);
- return {
- int16_t(util::clamp<int64_t>((zoomedCoord.p.x - tileID.canonical.x - tileID.wrap * std::pow(2, tileID.canonical.z)) * util::EXTENT,
- std::numeric_limits<int16_t>::min(),
- std::numeric_limits<int16_t>::max())),
- int16_t(util::clamp<int64_t>((zoomedCoord.p.y - tileID.canonical.y) * util::EXTENT,
- std::numeric_limits<int16_t>::min(),
- std::numeric_limits<int16_t>::max()))
- };
-}
-
-std::unordered_map<std::string, std::vector<Feature>> Source::queryRenderedFeatures(const QueryParameters& parameters) const {
- LineString<double> queryGeometry;
-
- for (const auto& p : parameters.geometry) {
- queryGeometry.push_back(TileCoordinate::fromScreenCoordinate(
- parameters.transformState, 0, { p.x, parameters.transformState.getHeight() - p.y }).p);
- }
-
- mapbox::geometry::box<double> box = mapbox::geometry::envelope(queryGeometry);
-
- std::unordered_map<std::string, std::vector<Feature>> result;
-
- for (const auto& tilePtr : tiles) {
- const Tile& tile = tilePtr.second;
-
- Point<int16_t> tileSpaceBoundsMin = coordinateToTilePoint(tile.id, box.min);
- Point<int16_t> tileSpaceBoundsMax = coordinateToTilePoint(tile.id, box.max);
-
- if (tileSpaceBoundsMin.x >= util::EXTENT || tileSpaceBoundsMin.y >= util::EXTENT ||
- tileSpaceBoundsMax.x < 0 || tileSpaceBoundsMax.y < 0) continue;
-
- GeometryCoordinates tileSpaceQueryGeometry;
-
- for (const auto& c : queryGeometry) {
- tileSpaceQueryGeometry.push_back(coordinateToTilePoint(tile.id, c));
- }
-
- tile.data.queryRenderedFeatures(result,
- tileSpaceQueryGeometry,
- parameters.transformState,
- parameters.layerIDs);
- }
-
- return result;
-}
-
-void Source::setCacheSize(size_t size) {
- cache.setSize(size);
-}
-
-void Source::onLowMemory() {
- cache.clear();
-}
-
-void Source::setObserver(SourceObserver* observer_) {
- observer = observer_;
-}
-
-void Source::tileLoadingCallback(const OverscaledTileID& tileID,
- std::exception_ptr error,
- bool isNewTile) {
- auto it = tileDataMap.find(tileID);
- if (it == tileDataMap.end()) {
- return;
- }
-
- auto& tileData = it->second;
- if (!tileData) {
- return;
- }
-
- if (error) {
- observer->onTileError(*this, tileID, error);
- return;
- }
-
- tileData->redoPlacement([this]() {
- observer->onPlacementRedone();
- });
- observer->onTileLoaded(*this, tileID, isNewTile);
-}
-
-void Source::dumpDebugLogs() const {
- Log::Info(Event::General, "Source::id: %s", id.c_str());
- Log::Info(Event::General, "Source::loaded: %d", loaded);
-
- for (const auto& pair : tileDataMap) {
- auto& tileData = pair.second;
- tileData->dumpDebugLogs();
- }
+const std::string& Source::getID() const {
+ return baseImpl->id;
}
} // namespace style
diff --git a/src/mbgl/style/source.hpp b/src/mbgl/style/source.hpp
deleted file mode 100644
index 07e1aeaf58..0000000000
--- a/src/mbgl/style/source.hpp
+++ /dev/null
@@ -1,112 +0,0 @@
-#pragma once
-
-#include <mbgl/tile/tile_id.hpp>
-#include <mbgl/tile/tile_data.hpp>
-#include <mbgl/tile/tile_cache.hpp>
-#include <mbgl/style/types.hpp>
-
-#include <mbgl/util/mat4.hpp>
-#include <mbgl/util/rapidjson.hpp>
-#include <mbgl/util/feature.hpp>
-#include <mbgl/util/tileset.hpp>
-
-#include <forward_list>
-#include <vector>
-#include <map>
-
-namespace mapbox {
-namespace geojsonvt {
-class GeoJSONVT;
-} // namespace geojsonvt
-} // namespace mapbox
-
-namespace mbgl {
-
-class Painter;
-class FileSource;
-class AsyncRequest;
-class TransformState;
-class Tile;
-struct ClipID;
-
-namespace style {
-
-class Style;
-class UpdateParameters;
-class QueryParameters;
-class SourceObserver;
-
-class Source : private util::noncopyable {
-public:
- Source(SourceType,
- const std::string& id,
- const std::string& url,
- uint16_t tileSize,
- std::unique_ptr<Tileset>&&,
- std::unique_ptr<mapbox::geojsonvt::GeoJSONVT>&&);
- ~Source();
-
- bool loaded = false;
- void load(FileSource&);
- bool isLoading() const;
- bool isLoaded() const;
-
- const Tileset* getTileset() const { return tileset.get(); }
-
- // Request or parse all the tiles relevant for the "TransformState". This method
- // will return true if all the tiles were scheduled for updating of false if
- // they were not. shouldReparsePartialTiles must be set to "true" if there is
- // new data available that a tile in the "partial" state might be interested at.
- bool update(const UpdateParameters&);
-
- template <typename ClipIDGenerator>
- void updateClipIDs(ClipIDGenerator& generator) {
- generator.update(tiles);
- }
-
- void updateMatrices(const mat4 &projMatrix, const TransformState &transform);
- void finishRender(Painter &painter);
-
- const std::map<UnwrappedTileID, Tile>& getTiles() const;
-
- TileData* getTileData(const OverscaledTileID&) const;
-
- std::unordered_map<std::string, std::vector<Feature>>
- queryRenderedFeatures(const QueryParameters&) const;
-
- void setCacheSize(size_t);
- void onLowMemory();
-
- void setObserver(SourceObserver* observer);
- void dumpDebugLogs() const;
-
- const SourceType type;
- const std::string id;
- const std::string url;
- uint16_t tileSize = util::tileSize;
- bool enabled = false;
-
-private:
- void tileLoadingCallback(const OverscaledTileID&, std::exception_ptr, bool isNewTile);
-
- std::unique_ptr<TileData> createTile(const OverscaledTileID&, const UpdateParameters&);
-
-private:
- std::unique_ptr<const Tileset> tileset;
-
- std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> geojsonvt;
-
- // Stores the time when this source was most recently updated.
- TimePoint updated = TimePoint::min();
-
- std::map<UnwrappedTileID, Tile> tiles;
- std::map<OverscaledTileID, std::unique_ptr<TileData>> tileDataMap;
- TileCache cache;
-
- std::unique_ptr<AsyncRequest> req;
-
- SourceObserver* observer = nullptr;
-};
-
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/style/source_impl.cpp b/src/mbgl/style/source_impl.cpp
new file mode 100644
index 0000000000..95363ca699
--- /dev/null
+++ b/src/mbgl/style/source_impl.cpp
@@ -0,0 +1,287 @@
+#include <mbgl/style/source_impl.hpp>
+#include <mbgl/style/source_observer.hpp>
+#include <mbgl/map/transform.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/style/update_parameters.hpp>
+#include <mbgl/style/query_parameters.hpp>
+#include <mbgl/platform/log.hpp>
+#include <mbgl/math/clamp.hpp>
+#include <mbgl/util/tile_cover.hpp>
+#include <mbgl/util/enum.hpp>
+
+#include <mbgl/algorithm/update_renderables.hpp>
+#include <mbgl/algorithm/generate_clip_ids.hpp>
+#include <mbgl/algorithm/generate_clip_ids_impl.hpp>
+
+#include <mapbox/geometry/envelope.hpp>
+
+#include <algorithm>
+
+namespace mbgl {
+namespace style {
+
+static SourceObserver nullObserver;
+
+Source::Impl::Impl(SourceType type_, std::string id_, Source& base_)
+ : type(type_),
+ id(std::move(id_)),
+ base(base_),
+ observer(&nullObserver) {
+}
+
+Source::Impl::~Impl() = default;
+
+bool Source::Impl::isLoaded() const {
+ if (!loaded) return false;
+
+ for (const auto& pair : tiles) {
+ if (!pair.second->isComplete()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void Source::Impl::invalidateTiles() {
+ tiles.clear();
+ renderTiles.clear();
+ cache.clear();
+}
+
+void Source::Impl::startRender(algorithm::ClipIDGenerator& generator,
+ const mat4& projMatrix,
+ const TransformState& transform) {
+ if (type == SourceType::Vector ||
+ type == SourceType::GeoJSON ||
+ type == SourceType::Annotations) {
+ generator.update(renderTiles);
+ }
+
+ for (auto& pair : renderTiles) {
+ auto& tile = pair.second;
+ transform.matrixFor(tile.matrix, tile.id);
+ matrix::multiply(tile.matrix, projMatrix, tile.matrix);
+ }
+}
+
+void Source::Impl::finishRender(Painter& painter) {
+ for (auto& pair : renderTiles) {
+ auto& tile = pair.second;
+ painter.renderTileDebug(tile);
+ }
+}
+
+const std::map<UnwrappedTileID, RenderTile>& Source::Impl::getRenderTiles() const {
+ return renderTiles;
+}
+
+Tile* Source::Impl::getTile(const OverscaledTileID& overscaledTileID) const {
+ auto it = tiles.find(overscaledTileID);
+ if (it != tiles.end()) {
+ return it->second.get();
+ } else {
+ return nullptr;
+ }
+}
+
+bool Source::Impl::update(const UpdateParameters& parameters) {
+ bool allTilesUpdated = true;
+
+ if (!loaded || parameters.animationTime <= updated) {
+ return allTilesUpdated;
+ }
+
+ const uint16_t tileSize = getTileSize();
+ const Range<uint8_t> zoomRange = getZoomRange();
+
+ // Determine the overzooming/underzooming amounts and required tiles.
+ int32_t overscaledZoom = util::coveringZoomLevel(parameters.transformState.getZoom(), type, tileSize);
+ int32_t dataTileZoom = overscaledZoom;
+
+ std::vector<UnwrappedTileID> idealTiles;
+ if (overscaledZoom >= zoomRange.min) {
+ int32_t idealZoom = std::min<int32_t>(zoomRange.max, overscaledZoom);
+
+ // Make sure we're not reparsing overzoomed raster tiles.
+ if (type == SourceType::Raster) {
+ dataTileZoom = idealZoom;
+ }
+
+ idealTiles = util::tileCover(parameters.transformState, idealZoom);
+ }
+
+ // Stores a list of all the data tiles that we're definitely going to retain. There are two
+ // kinds of tiles we need: the ideal tiles determined by the tile cover. They may not yet be in
+ // use because they're still loading. In addition to that, we also need to retain all tiles that
+ // we're actively using, e.g. as a replacement for tile that aren't loaded yet.
+ std::set<OverscaledTileID> retain;
+
+ auto retainTileFn = [&retain](Tile& tile, bool required) -> void {
+ retain.emplace(tile.id);
+ tile.setNecessity(required ? Tile::Necessity::Required
+ : Tile::Necessity::Optional);
+ };
+ auto getTileFn = [this](const OverscaledTileID& dataTileID) -> Tile* {
+ return getTile(dataTileID);
+ };
+ auto createTileFn = [this, &parameters](const OverscaledTileID& dataTileID) -> Tile* {
+ std::unique_ptr<Tile> data = cache.get(dataTileID);
+ if (!data) {
+ data = createTile(dataTileID, parameters);
+ if (data) {
+ data->setObserver(this);
+ }
+ }
+ if (data) {
+ return tiles.emplace(dataTileID, std::move(data)).first->second.get();
+ } else {
+ return nullptr;
+ }
+ };
+ auto renderTileFn = [this](const UnwrappedTileID& renderTileID, Tile& tile) {
+ renderTiles.emplace(renderTileID, RenderTile{ renderTileID, tile });
+ };
+
+ renderTiles.clear();
+ algorithm::updateRenderables(getTileFn, createTileFn, retainTileFn, renderTileFn,
+ idealTiles, zoomRange, dataTileZoom);
+
+ if (type != SourceType::Raster && type != SourceType::Annotations && cache.getSize() == 0) {
+ size_t conservativeCacheSize =
+ ((float)parameters.transformState.getWidth() / util::tileSize) *
+ ((float)parameters.transformState.getHeight() / util::tileSize) *
+ (parameters.transformState.getMaxZoom() - parameters.transformState.getMinZoom() + 1) *
+ 0.5;
+ cache.setSize(conservativeCacheSize);
+ }
+
+ // Remove stale data tiles from the active set of tiles.
+ // This goes through the (sorted!) tiles and retain set in lockstep and removes items from
+ // tiles that don't have the corresponding key in the retain set.
+ auto dataIt = tiles.begin();
+ auto retainIt = retain.begin();
+ while (dataIt != tiles.end()) {
+ if (retainIt == retain.end() || dataIt->first < *retainIt) {
+ dataIt->second->setNecessity(Tile::Necessity::Optional);
+ cache.add(dataIt->first, std::move(dataIt->second));
+ tiles.erase(dataIt++);
+ } else {
+ if (!(*retainIt < dataIt->first)) {
+ ++dataIt;
+ }
+ ++retainIt;
+ }
+ }
+
+ const PlacementConfig newConfig{ parameters.transformState.getAngle(),
+ parameters.transformState.getPitch(),
+ parameters.debugOptions & MapDebugOptions::Collision };
+ for (auto& pair : tiles) {
+ auto tile = pair.second.get();
+ if (parameters.shouldReparsePartialTiles && tile->isIncomplete()) {
+ if (!tile->parsePending()) {
+ allTilesUpdated = false;
+ }
+ } else {
+ tile->redoPlacement(newConfig);
+ }
+ }
+
+ updated = parameters.animationTime;
+
+ return allTilesUpdated;
+}
+
+static Point<int16_t> coordinateToTilePoint(const UnwrappedTileID& tileID, const Point<double>& p) {
+ auto zoomedCoord = TileCoordinate { p, 0 }.zoomTo(tileID.canonical.z);
+ return {
+ int16_t(util::clamp<int64_t>((zoomedCoord.p.x - tileID.canonical.x - tileID.wrap * std::pow(2, tileID.canonical.z)) * util::EXTENT,
+ std::numeric_limits<int16_t>::min(),
+ std::numeric_limits<int16_t>::max())),
+ int16_t(util::clamp<int64_t>((zoomedCoord.p.y - tileID.canonical.y) * util::EXTENT,
+ std::numeric_limits<int16_t>::min(),
+ std::numeric_limits<int16_t>::max()))
+ };
+}
+
+std::unordered_map<std::string, std::vector<Feature>> Source::Impl::queryRenderedFeatures(const QueryParameters& parameters) const {
+ std::unordered_map<std::string, std::vector<Feature>> result;
+ if (renderTiles.empty()) {
+ return result;
+ }
+
+ LineString<double> queryGeometry;
+
+ for (const auto& p : parameters.geometry) {
+ queryGeometry.push_back(TileCoordinate::fromScreenCoordinate(
+ parameters.transformState, 0, { p.x, parameters.transformState.getHeight() - p.y }).p);
+ }
+
+ if (queryGeometry.empty()) {
+ return result;
+ }
+
+ mapbox::geometry::box<double> box = mapbox::geometry::envelope(queryGeometry);
+
+ for (const auto& tilePtr : renderTiles) {
+ const RenderTile& tile = tilePtr.second;
+
+ Point<int16_t> tileSpaceBoundsMin = coordinateToTilePoint(tile.id, box.min);
+ Point<int16_t> tileSpaceBoundsMax = coordinateToTilePoint(tile.id, box.max);
+
+ if (tileSpaceBoundsMin.x >= util::EXTENT || tileSpaceBoundsMin.y >= util::EXTENT ||
+ tileSpaceBoundsMax.x < 0 || tileSpaceBoundsMax.y < 0) continue;
+
+ GeometryCoordinates tileSpaceQueryGeometry;
+
+ for (const auto& c : queryGeometry) {
+ tileSpaceQueryGeometry.push_back(coordinateToTilePoint(tile.id, c));
+ }
+
+ tile.tile.queryRenderedFeatures(result,
+ tileSpaceQueryGeometry,
+ parameters.transformState,
+ parameters.layerIDs);
+ }
+
+ return result;
+}
+
+void Source::Impl::setCacheSize(size_t size) {
+ cache.setSize(size);
+}
+
+void Source::Impl::onLowMemory() {
+ cache.clear();
+}
+
+void Source::Impl::setObserver(SourceObserver* observer_) {
+ observer = observer_;
+}
+
+void Source::Impl::onTileLoaded(Tile& tile, bool isNewTile) {
+ observer->onTileLoaded(base, tile.id, isNewTile);
+}
+
+void Source::Impl::onTileError(Tile& tile, std::exception_ptr error) {
+ observer->onTileError(base, tile.id, error);
+}
+
+void Source::Impl::onNeedsRepaint() {
+ observer->onNeedsRepaint();
+}
+
+void Source::Impl::dumpDebugLogs() const {
+ Log::Info(Event::General, "Source::id: %s", base.getID().c_str());
+ Log::Info(Event::General, "Source::loaded: %d", loaded);
+
+ for (const auto& pair : tiles) {
+ auto& tile = pair.second;
+ tile->dumpDebugLogs();
+ }
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/source_impl.hpp b/src/mbgl/style/source_impl.hpp
new file mode 100644
index 0000000000..64651d7e3f
--- /dev/null
+++ b/src/mbgl/style/source_impl.hpp
@@ -0,0 +1,101 @@
+#pragma once
+
+#include <mbgl/style/source.hpp>
+
+#include <mbgl/tile/tile_id.hpp>
+#include <mbgl/tile/tile_observer.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/tile/tile_cache.hpp>
+#include <mbgl/style/types.hpp>
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/mat4.hpp>
+#include <mbgl/util/feature.hpp>
+#include <mbgl/util/range.hpp>
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+#include <map>
+
+namespace mbgl {
+
+class Painter;
+class FileSource;
+class TransformState;
+class RenderTile;
+
+namespace algorithm {
+class ClipIDGenerator;
+} // namespace algorithm
+
+namespace style {
+
+class UpdateParameters;
+class QueryParameters;
+class SourceObserver;
+
+class Source::Impl : public TileObserver, private util::noncopyable {
+public:
+ Impl(SourceType, std::string id, Source&);
+ ~Impl() override;
+
+ virtual void load(FileSource&) = 0;
+ bool isLoaded() const;
+
+ // Request or parse all the tiles relevant for the "TransformState". This method
+ // will return true if all the tiles were scheduled for updating of false if
+ // they were not. shouldReparsePartialTiles must be set to "true" if there is
+ // new data available that a tile in the "partial" state might be interested at.
+ bool update(const UpdateParameters&);
+
+ void startRender(algorithm::ClipIDGenerator&,
+ const mat4& projMatrix,
+ const TransformState&);
+ void finishRender(Painter&);
+
+ const std::map<UnwrappedTileID, RenderTile>& getRenderTiles() const;
+
+ Tile* getTile(const OverscaledTileID&) const;
+
+ std::unordered_map<std::string, std::vector<Feature>>
+ queryRenderedFeatures(const QueryParameters&) const;
+
+ void setCacheSize(size_t);
+ void onLowMemory();
+
+ void setObserver(SourceObserver*);
+ void dumpDebugLogs() const;
+
+ const SourceType type;
+ const std::string id;
+
+ bool loaded = false;
+ bool enabled = false;
+
+protected:
+ void invalidateTiles();
+
+ Source& base;
+ SourceObserver* observer = nullptr;
+
+private:
+ // TileObserver implementation.
+ void onTileLoaded(Tile&, bool isNewTile) override;
+ void onTileError(Tile&, std::exception_ptr) override;
+ void onNeedsRepaint() override;
+
+ virtual uint16_t getTileSize() const = 0;
+ virtual Range<uint8_t> getZoomRange() = 0;
+ virtual std::unique_ptr<Tile> createTile(const OverscaledTileID&, const UpdateParameters&) = 0;
+
+ // Stores the time when this source was most recently updated.
+ TimePoint updated = TimePoint::min();
+
+ std::map<OverscaledTileID, std::unique_ptr<Tile>> tiles;
+ std::map<UnwrappedTileID, RenderTile> renderTiles;
+ TileCache cache;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/source_observer.hpp b/src/mbgl/style/source_observer.hpp
index a669e8e756..020ead4dba 100644
--- a/src/mbgl/style/source_observer.hpp
+++ b/src/mbgl/style/source_observer.hpp
@@ -18,7 +18,7 @@ public:
virtual void onSourceError(Source&, std::exception_ptr) {}
virtual void onTileLoaded(Source&, const OverscaledTileID&, bool /* isNewTile */) {}
virtual void onTileError(Source&, const OverscaledTileID&, std::exception_ptr) {}
- virtual void onPlacementRedone() {}
+ virtual void onNeedsRepaint() {}
};
} // namespace style
diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp
new file mode 100644
index 0000000000..2bf27880b4
--- /dev/null
+++ b/src/mbgl/style/sources/geojson_source.cpp
@@ -0,0 +1,26 @@
+#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/style/sources/geojson_source_impl.hpp>
+
+namespace mbgl {
+namespace style {
+
+GeoJSONSource::GeoJSONSource(const std::string& id, const GeoJSONOptions options)
+ : Source(SourceType::GeoJSON,
+ std::make_unique<GeoJSONSource::Impl>(std::move(id), *this, options)),
+ impl(static_cast<Impl*>(baseImpl.get())) {
+}
+
+void GeoJSONSource::setURL(const std::string& url) {
+ impl->setURL(url);
+}
+
+void GeoJSONSource::setGeoJSON(const mapbox::geojson::geojson& geoJSON) {
+ impl->setGeoJSON(geoJSON);
+}
+
+std::string GeoJSONSource::getURL() {
+ return impl->getURL();
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp
new file mode 100644
index 0000000000..0821ac0232
--- /dev/null
+++ b/src/mbgl/style/sources/geojson_source_impl.cpp
@@ -0,0 +1,142 @@
+#include <mbgl/platform/log.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/style/conversion/geojson.hpp>
+#include <mbgl/style/source_observer.hpp>
+#include <mbgl/style/sources/geojson_source_impl.hpp>
+#include <mbgl/tile/geojson_tile.hpp>
+#include <mbgl/util/rapidjson.hpp>
+
+#include <mapbox/geojson.hpp>
+#include <mapbox/geojson/rapidjson.hpp>
+#include <mapbox/geojsonvt.hpp>
+#include <mapbox/geojsonvt/convert.hpp>
+#include <supercluster.hpp>
+
+#include <rapidjson/error/en.h>
+
+#include <sstream>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <>
+Result<GeoJSON> convertGeoJSON(const JSValue& value) {
+ try {
+ return mapbox::geojson::convert(value);
+ } catch (const std::exception& ex) {
+ return Error{ ex.what() };
+ }
+}
+} // namespace conversion
+
+GeoJSONSource::Impl::Impl(std::string id_, Source& base_, const GeoJSONOptions options_)
+ : Source::Impl(SourceType::GeoJSON, std::move(id_), base_), options(options_) {
+}
+
+GeoJSONSource::Impl::~Impl() = default;
+
+void GeoJSONSource::Impl::setURL(std::string url) {
+ urlOrGeoJSON = std::move(url);
+}
+
+std::string GeoJSONSource::Impl::getURL() {
+ assert(urlOrGeoJSON.is<std::string>());
+ return urlOrGeoJSON.get<std::string>();
+}
+
+void GeoJSONSource::Impl::setGeoJSON(const GeoJSON& geoJSON) {
+ double scale = util::EXTENT / util::tileSize;
+
+ if (!options.cluster) {
+ mapbox::geojsonvt::Options vtOptions;
+ vtOptions.maxZoom = options.maxzoom;
+ vtOptions.extent = util::EXTENT;
+ vtOptions.buffer = std::round(scale * options.buffer);
+ vtOptions.tolerance = scale * options.tolerance;
+ urlOrGeoJSON = std::make_unique<mapbox::geojsonvt::GeoJSONVT>(geoJSON, vtOptions);
+
+ } else {
+ mapbox::supercluster::Options clusterOptions;
+ clusterOptions.maxZoom = options.clusterMaxZoom;
+ clusterOptions.extent = util::EXTENT;
+ clusterOptions.radius = std::round(scale * options.clusterRadius);
+
+ const auto& features = geoJSON.get<mapbox::geometry::feature_collection<double>>();
+ urlOrGeoJSON =
+ std::make_unique<mapbox::supercluster::Supercluster>(features, clusterOptions);
+ }
+}
+
+void GeoJSONSource::Impl::load(FileSource& fileSource) {
+ if (!urlOrGeoJSON.is<std::string>()) {
+ loaded = true;
+ return;
+ }
+
+ if (req) {
+ return;
+ }
+
+ const std::string& url = urlOrGeoJSON.get<std::string>();
+ req = fileSource.request(Resource::source(url), [this](Response res) {
+ if (res.error) {
+ observer->onSourceError(
+ base, std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
+ return;
+ } else if (res.noContent) {
+ observer->onSourceError(
+ base, std::make_exception_ptr(std::runtime_error("unexpectedly empty GeoJSON")));
+ } else {
+ rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> d;
+ d.Parse<0>(res.data->c_str());
+
+ if (d.HasParseError()) {
+ std::stringstream message;
+ message << d.GetErrorOffset() << " - "
+ << rapidjson::GetParseError_En(d.GetParseError());
+ observer->onSourceError(base,
+ std::make_exception_ptr(std::runtime_error(message.str())));
+ return;
+ }
+
+ invalidateTiles();
+
+ conversion::Result<GeoJSON> geoJSON = conversion::convertGeoJSON<JSValue>(d);
+ if (!geoJSON) {
+ Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s",
+ geoJSON.error().message.c_str());
+ // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for
+ // tiles to load.
+ setGeoJSON(GeoJSON{ FeatureCollection{} });
+ } else {
+ setGeoJSON(*geoJSON);
+ }
+
+ loaded = true;
+ observer->onSourceLoaded(base);
+ }
+ });
+}
+
+Range<uint8_t> GeoJSONSource::Impl::getZoomRange() {
+ assert(loaded);
+ return { 0, options.maxzoom };
+}
+
+std::unique_ptr<Tile> GeoJSONSource::Impl::createTile(const OverscaledTileID& tileID,
+ const UpdateParameters& parameters) {
+ assert(loaded);
+ if (urlOrGeoJSON.is<GeoJSONVTPointer>()) {
+ return std::make_unique<GeoJSONTile>(tileID, base.getID(), parameters,
+ *urlOrGeoJSON.get<GeoJSONVTPointer>());
+ } else {
+ assert(urlOrGeoJSON.is<SuperclusterPointer>());
+ return std::make_unique<GeoJSONTile>(tileID, base.getID(), parameters,
+ *urlOrGeoJSON.get<SuperclusterPointer>());
+ }
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/sources/geojson_source_impl.hpp b/src/mbgl/style/sources/geojson_source_impl.hpp
new file mode 100644
index 0000000000..eb3563e85a
--- /dev/null
+++ b/src/mbgl/style/sources/geojson_source_impl.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <mbgl/style/source_impl.hpp>
+#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/util/variant.hpp>
+
+namespace mbgl {
+
+class AsyncRequest;
+
+namespace style {
+
+class GeoJSONSource::Impl : public Source::Impl {
+public:
+ Impl(std::string id, Source&, const GeoJSONOptions);
+ ~Impl() final;
+
+ void setURL(std::string);
+ void setGeoJSON(const GeoJSON&);
+
+ std::string getURL();
+
+ void load(FileSource&) final;
+
+ uint16_t getTileSize() const final {
+ return util::tileSize;
+ }
+
+private:
+ Range<uint8_t> getZoomRange() final;
+ std::unique_ptr<Tile> createTile(const OverscaledTileID&, const UpdateParameters&) final;
+
+ variant<std::string, GeoJSONVTPointer, SuperclusterPointer> urlOrGeoJSON;
+ std::unique_ptr<AsyncRequest> req;
+
+ GeoJSONOptions options;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/sources/raster_source.cpp b/src/mbgl/style/sources/raster_source.cpp
new file mode 100644
index 0000000000..3c65476df0
--- /dev/null
+++ b/src/mbgl/style/sources/raster_source.cpp
@@ -0,0 +1,12 @@
+#include <mbgl/style/sources/raster_source.hpp>
+#include <mbgl/style/sources/raster_source_impl.hpp>
+
+namespace mbgl {
+namespace style {
+
+RasterSource::RasterSource(std::string id, variant<std::string, Tileset> urlOrTileset, uint16_t tileSize)
+ : Source(SourceType::Raster, std::make_unique<RasterSource::Impl>(std::move(id), *this, std::move(urlOrTileset), tileSize)) {
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/sources/raster_source_impl.cpp b/src/mbgl/style/sources/raster_source_impl.cpp
new file mode 100644
index 0000000000..b727651260
--- /dev/null
+++ b/src/mbgl/style/sources/raster_source_impl.cpp
@@ -0,0 +1,19 @@
+#include <mbgl/style/sources/raster_source_impl.hpp>
+#include <mbgl/tile/raster_tile.hpp>
+
+namespace mbgl {
+namespace style {
+
+RasterSource::Impl::Impl(std::string id_, Source& base_,
+ variant<std::string, Tileset> urlOrTileset_,
+ uint16_t tileSize_)
+ : TileSourceImpl(SourceType::Raster, std::move(id_), base_, std::move(urlOrTileset_), tileSize_) {
+}
+
+std::unique_ptr<Tile> RasterSource::Impl::createTile(const OverscaledTileID& tileID,
+ const UpdateParameters& parameters) {
+ return std::make_unique<RasterTile>(tileID, parameters, tileset);
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/sources/raster_source_impl.hpp b/src/mbgl/style/sources/raster_source_impl.hpp
new file mode 100644
index 0000000000..6f34a050bb
--- /dev/null
+++ b/src/mbgl/style/sources/raster_source_impl.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <mbgl/style/sources/raster_source.hpp>
+#include <mbgl/style/tile_source_impl.hpp>
+
+namespace mbgl {
+namespace style {
+
+class RasterSource::Impl : public TileSourceImpl {
+public:
+ Impl(std::string id, Source&, variant<std::string, Tileset>, uint16_t tileSize);
+
+private:
+ std::unique_ptr<Tile> createTile(const OverscaledTileID&, const UpdateParameters&) final;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/sources/vector_source.cpp b/src/mbgl/style/sources/vector_source.cpp
new file mode 100644
index 0000000000..f2a6b166a9
--- /dev/null
+++ b/src/mbgl/style/sources/vector_source.cpp
@@ -0,0 +1,12 @@
+#include <mbgl/style/sources/vector_source.hpp>
+#include <mbgl/style/sources/vector_source_impl.hpp>
+
+namespace mbgl {
+namespace style {
+
+VectorSource::VectorSource(std::string id, variant<std::string, Tileset> urlOrTileset)
+ : Source(SourceType::Vector, std::make_unique<VectorSource::Impl>(std::move(id), *this, std::move(urlOrTileset))) {
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/sources/vector_source_impl.cpp b/src/mbgl/style/sources/vector_source_impl.cpp
new file mode 100644
index 0000000000..efe8afbbea
--- /dev/null
+++ b/src/mbgl/style/sources/vector_source_impl.cpp
@@ -0,0 +1,17 @@
+#include <mbgl/style/sources/vector_source_impl.hpp>
+#include <mbgl/tile/vector_tile.hpp>
+
+namespace mbgl {
+namespace style {
+
+VectorSource::Impl::Impl(std::string id_, Source& base_, variant<std::string, Tileset> urlOrTileset_)
+ : TileSourceImpl(SourceType::Vector, std::move(id_), base_, std::move(urlOrTileset_), util::tileSize) {
+}
+
+std::unique_ptr<Tile> VectorSource::Impl::createTile(const OverscaledTileID& tileID,
+ const UpdateParameters& parameters) {
+ return std::make_unique<VectorTile>(tileID, base.getID(), parameters, tileset);
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/sources/vector_source_impl.hpp b/src/mbgl/style/sources/vector_source_impl.hpp
new file mode 100644
index 0000000000..6726fa6955
--- /dev/null
+++ b/src/mbgl/style/sources/vector_source_impl.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <mbgl/style/sources/vector_source.hpp>
+#include <mbgl/style/tile_source_impl.hpp>
+
+namespace mbgl {
+namespace style {
+
+class VectorSource::Impl : public TileSourceImpl {
+public:
+ Impl(std::string id, Source&, variant<std::string, Tileset>);
+
+private:
+ std::unique_ptr<Tile> createTile(const OverscaledTileID&, const UpdateParameters&) final;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp
index d9b49d4309..ce33a409f7 100644
--- a/src/mbgl/style/style.cpp
+++ b/src/mbgl/style/style.cpp
@@ -1,6 +1,6 @@
#include <mbgl/style/style.hpp>
#include <mbgl/style/observer.hpp>
-#include <mbgl/style/source.hpp>
+#include <mbgl/style/source_impl.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
@@ -19,7 +19,7 @@
#include <mbgl/geometry/glyph_atlas.hpp>
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/renderer/render_item.hpp>
-#include <mbgl/tile/tile.hpp>
+#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/platform/log.hpp>
@@ -47,7 +47,7 @@ Style::Style(FileSource& fileSource_, float pixelRatio)
Style::~Style() {
for (const auto& source : sources) {
- source->setObserver(nullptr);
+ source->baseImpl->setObserver(nullptr);
}
glyphStore->setObserver(nullptr);
@@ -107,15 +107,24 @@ void Style::setJSON(const std::string& json) {
}
void Style::addSource(std::unique_ptr<Source> source) {
- source->setObserver(this);
+ source->baseImpl->setObserver(this);
sources.emplace_back(std::move(source));
}
-std::vector<std::unique_ptr<Layer>> Style::getLayers() const {
- std::vector<std::unique_ptr<Layer>> result;
+void Style::removeSource(const std::string& id) {
+ auto it = std::find_if(sources.begin(), sources.end(), [&](const auto& source) {
+ return source->getID() == id;
+ });
+ if (it == sources.end())
+ throw std::runtime_error("no such source");
+ sources.erase(it);
+}
+
+std::vector<const Layer*> Style::getLayers() const {
+ std::vector<const Layer*> result;
result.reserve(layers.size());
for (const auto& layer : layers) {
- result.push_back(layer->baseImpl->clone());
+ result.push_back(layer.get());
}
return result;
}
@@ -132,6 +141,8 @@ Layer* Style::getLayer(const std::string& id) const {
}
void Style::addLayer(std::unique_ptr<Layer> layer, optional<std::string> before) {
+ // TODO: verify source
+
if (SymbolLayer* symbolLayer = layer->as<SymbolLayer>()) {
if (!symbolLayer->impl->spriteAtlas) {
symbolLayer->impl->spriteAtlas = spriteAtlas.get();
@@ -156,7 +167,7 @@ void Style::update(const UpdateParameters& parameters) {
bool allTilesUpdated = true;
for (const auto& source : sources) {
- if (!source->update(parameters)) {
+ if (!source->baseImpl->update(parameters)) {
allTilesUpdated = false;
}
}
@@ -171,7 +182,7 @@ void Style::update(const UpdateParameters& parameters) {
void Style::cascade(const TimePoint& timePoint, MapMode mode) {
// When in continuous mode, we can either have user- or style-defined
// transitions. Still mode is always immediate.
- static const TransitionOptions immediateTransition;
+ static const TransitionOptions immediateTransition {};
std::vector<ClassID> classIDs;
for (const auto& className : classes) {
@@ -195,7 +206,7 @@ void Style::cascade(const TimePoint& timePoint, MapMode mode) {
void Style::recalculate(float z, const TimePoint& timePoint, MapMode mode) {
for (const auto& source : sources) {
- source->enabled = false;
+ source->baseImpl->enabled = false;
}
zoomHistory.update(z, timePoint);
@@ -213,9 +224,9 @@ void Style::recalculate(float z, const TimePoint& timePoint, MapMode mode) {
Source* source = getSource(layer->baseImpl->source);
if (source && layer->baseImpl->needsRendering(z)) {
- source->enabled = true;
- if (!source->loaded && !source->isLoading()) {
- source->load(fileSource);
+ source->baseImpl->enabled = true;
+ if (!source->baseImpl->loaded) {
+ source->baseImpl->load(fileSource);
}
}
}
@@ -223,7 +234,7 @@ void Style::recalculate(float z, const TimePoint& timePoint, MapMode mode) {
Source* Style::getSource(const std::string& id) const {
const auto it = std::find_if(sources.begin(), sources.end(), [&](const auto& source) {
- return source->id == id;
+ return source->getID() == id;
});
return it != sources.end() ? it->get() : nullptr;
@@ -239,7 +250,7 @@ bool Style::isLoaded() const {
}
for (const auto& source: sources) {
- if (source->enabled && !source->isLoaded()) return false;
+ if (source->baseImpl->enabled && !source->baseImpl->isLoaded()) return false;
}
if (!spriteStore->isLoaded()) {
@@ -249,11 +260,11 @@ bool Style::isLoaded() const {
return true;
}
-RenderData Style::getRenderData() const {
+RenderData Style::getRenderData(MapDebugOptions debugOptions) const {
RenderData result;
for (const auto& source : sources) {
- if (source->enabled) {
+ if (source->baseImpl->enabled) {
result.sources.insert(source.get());
}
}
@@ -263,14 +274,15 @@ RenderData Style::getRenderData() const {
continue;
if (const BackgroundLayer* background = layer->as<BackgroundLayer>()) {
+ if (debugOptions & MapDebugOptions::Overdraw) {
+ // We want to skip glClear optimization in overdraw mode.
+ result.order.emplace_back(*layer);
+ continue;
+ }
const BackgroundPaintProperties& paint = background->impl->paint;
if (layer.get() == layers[0].get() && paint.backgroundPattern.value.from.empty()) {
// This is a solid background. We can use glClear().
- result.backgroundColor = paint.backgroundColor;
- result.backgroundColor[0] *= paint.backgroundOpacity;
- result.backgroundColor[1] *= paint.backgroundOpacity;
- result.backgroundColor[2] *= paint.backgroundOpacity;
- result.backgroundColor[3] *= paint.backgroundOpacity;
+ result.backgroundColor = paint.backgroundColor * paint.backgroundOpacity;
} else {
// This is a textured background, or not the bottommost layer. We need to render it with a quad.
result.order.emplace_back(*layer);
@@ -289,9 +301,9 @@ RenderData Style::getRenderData() const {
continue;
}
- for (auto& pair : source->getTiles()) {
+ for (auto& pair : source->baseImpl->getRenderTiles()) {
auto& tile = pair.second;
- if (!tile.data.isRenderable()) {
+ if (!tile.tile.isRenderable()) {
continue;
}
@@ -304,7 +316,7 @@ RenderData Style::getRenderData() const {
// already a bucket from this layer that is a parent of this tile. Tiles are ordered
// by zoom level when we obtain them from getTiles().
for (auto it = result.order.rbegin(); it != result.order.rend() && (&it->layer == layer.get()); ++it) {
- if (tile.data.id.isChildOf(it->tile->data.id)) {
+ if (tile.tile.id.isChildOf(it->tile->tile.id)) {
skip = true;
break;
}
@@ -314,7 +326,7 @@ RenderData Style::getRenderData() const {
}
}
- auto bucket = tile.data.getBucket(*layer);
+ auto bucket = tile.tile.getBucket(*layer);
if (bucket) {
result.order.emplace_back(*layer, &tile, bucket);
}
@@ -325,14 +337,17 @@ RenderData Style::getRenderData() const {
}
std::vector<Feature> Style::queryRenderedFeatures(const QueryParameters& parameters) const {
+ std::vector<Feature> result;
std::unordered_map<std::string, std::vector<Feature>> resultsByLayer;
for (const auto& source : sources) {
- auto sourceResults = source->queryRenderedFeatures(parameters);
+ auto sourceResults = source->baseImpl->queryRenderedFeatures(parameters);
std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin()));
}
- std::vector<Feature> result;
+ if (resultsByLayer.empty()) {
+ return result;
+ }
// Combine all results based on the style layer order.
for (const auto& layer : layers) {
@@ -356,13 +371,13 @@ float Style::getQueryRadius() const {
void Style::setSourceTileCacheSize(size_t size) {
for (const auto& source : sources) {
- source->setCacheSize(size);
+ source->baseImpl->setCacheSize(size);
}
}
void Style::onLowMemory() {
for (const auto& source : sources) {
- source->onLowMemory();
+ source->baseImpl->onLowMemory();
}
}
@@ -373,7 +388,7 @@ void Style::setObserver(style::Observer* observer_) {
void Style::onGlyphsLoaded(const FontStack& fontStack, const GlyphRange& glyphRange) {
shouldReparsePartialTiles = true;
observer->onGlyphsLoaded(fontStack, glyphRange);
- observer->onResourceLoaded();
+ observer->onNeedsRepaint();
}
void Style::onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) {
@@ -386,13 +401,13 @@ void Style::onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRan
void Style::onSourceLoaded(Source& source) {
observer->onSourceLoaded(source);
- observer->onResourceLoaded();
+ observer->onNeedsRepaint();
}
void Style::onSourceError(Source& source, std::exception_ptr error) {
lastError = error;
Log::Error(Event::Style, "Failed to load source %s: %s",
- source.id.c_str(), util::toString(error).c_str());
+ source.getID().c_str(), util::toString(error).c_str());
observer->onSourceError(source, error);
observer->onResourceError(error);
}
@@ -403,25 +418,25 @@ void Style::onTileLoaded(Source& source, const OverscaledTileID& tileID, bool is
}
observer->onTileLoaded(source, tileID, isNewTile);
- observer->onResourceLoaded();
+ observer->onNeedsRepaint();
}
void Style::onTileError(Source& source, const OverscaledTileID& tileID, std::exception_ptr error) {
lastError = error;
Log::Error(Event::Style, "Failed to load tile %s for source %s: %s",
- util::toString(tileID).c_str(), source.id.c_str(), util::toString(error).c_str());
+ util::toString(tileID).c_str(), source.getID().c_str(), util::toString(error).c_str());
observer->onTileError(source, tileID, error);
observer->onResourceError(error);
}
-void Style::onPlacementRedone() {
- observer->onResourceLoaded();
+void Style::onNeedsRepaint() {
+ observer->onNeedsRepaint();
}
void Style::onSpriteLoaded() {
shouldReparsePartialTiles = true;
observer->onSpriteLoaded();
- observer->onResourceLoaded();
+ observer->onNeedsRepaint();
}
void Style::onSpriteError(std::exception_ptr error) {
@@ -433,7 +448,7 @@ void Style::onSpriteError(std::exception_ptr error) {
void Style::dumpDebugLogs() const {
for (const auto& source : sources) {
- source->dumpDebugLogs();
+ source->baseImpl->dumpDebugLogs();
}
spriteStore->dumpDebugLogs();
diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp
index 05a975a95a..35369ffca3 100644
--- a/src/mbgl/style/style.hpp
+++ b/src/mbgl/style/style.hpp
@@ -37,7 +37,7 @@ class Style : public GlyphStoreObserver,
public util::noncopyable {
public:
Style(FileSource&, float pixelRatio);
- ~Style();
+ ~Style() override;
void setJSON(const std::string&);
@@ -60,8 +60,9 @@ public:
Source* getSource(const std::string& id) const;
void addSource(std::unique_ptr<Source>);
+ void removeSource(const std::string& sourceID);
- std::vector<std::unique_ptr<Layer>> getLayers() const;
+ std::vector<const Layer*> getLayers() const;
Layer* getLayer(const std::string& id) const;
void addLayer(std::unique_ptr<Layer>,
optional<std::string> beforeLayerID = {});
@@ -73,7 +74,7 @@ public:
void setClasses(const std::vector<std::string>&, const TransitionOptions& = {});
std::vector<std::string> getClasses() const;
- RenderData getRenderData() const;
+ RenderData getRenderData(MapDebugOptions) const;
std::vector<Feature> queryRenderedFeatures(const QueryParameters&) const;
@@ -112,7 +113,7 @@ private:
void onSourceError(Source&, std::exception_ptr) override;
void onTileLoaded(Source&, const OverscaledTileID&, bool isNewTile) override;
void onTileError(Source&, const OverscaledTileID&, std::exception_ptr) override;
- void onPlacementRedone() override;
+ void onNeedsRepaint() override;
Observer nullObserver;
Observer* observer = &nullObserver;
diff --git a/src/mbgl/style/tile_source_impl.cpp b/src/mbgl/style/tile_source_impl.cpp
new file mode 100644
index 0000000000..3999a88a07
--- /dev/null
+++ b/src/mbgl/style/tile_source_impl.cpp
@@ -0,0 +1,118 @@
+#include <mbgl/style/tile_source_impl.hpp>
+#include <mbgl/style/source_observer.hpp>
+#include <mbgl/style/rapidjson_conversion.hpp>
+#include <mbgl/style/conversion/tileset.hpp>
+#include <mbgl/util/tileset.hpp>
+#include <mbgl/util/mapbox.hpp>
+#include <mbgl/storage/file_source.hpp>
+
+#include <rapidjson/document.h>
+#include <rapidjson/error/en.h>
+
+#include <sstream>
+
+namespace mbgl {
+namespace style {
+
+Tileset TileSourceImpl::parseTileJSON(const std::string& json, const std::string& sourceURL, SourceType type, uint16_t tileSize) {
+ rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> document;
+ document.Parse<0>(json.c_str());
+
+ if (document.HasParseError()) {
+ std::stringstream message;
+ message << document.GetErrorOffset() << " - " << rapidjson::GetParseError_En(document.GetParseError());
+ throw std::runtime_error(message.str());
+ }
+
+ conversion::Result<Tileset> result = conversion::convert<Tileset>(document);
+ if (!result) {
+ throw std::runtime_error(result.error().message);
+ }
+
+ // TODO: Remove this hack by delivering proper URLs in the TileJSON to begin with.
+ if (util::mapbox::isMapboxURL(sourceURL)) {
+ for (auto& url : (*result).tiles) {
+ url = util::mapbox::canonicalizeTileURL(url, type, tileSize);
+ }
+ }
+
+ return *result;
+}
+
+TileSourceImpl::TileSourceImpl(SourceType type_, std::string id_, Source& base_,
+ variant<std::string, Tileset> urlOrTileset_,
+ uint16_t tileSize_)
+ : Impl(type_, std::move(id_), base_),
+ urlOrTileset(std::move(urlOrTileset_)),
+ tileSize(tileSize_) {
+}
+
+TileSourceImpl::~TileSourceImpl() = default;
+
+void TileSourceImpl::load(FileSource& fileSource) {
+ if (urlOrTileset.is<Tileset>()) {
+ tileset = urlOrTileset.get<Tileset>();
+ loaded = true;
+ return;
+ }
+
+ if (req) {
+ return;
+ }
+
+ const std::string& url = urlOrTileset.get<std::string>();
+ req = fileSource.request(Resource::source(url), [this, url](Response res) {
+ if (res.error) {
+ observer->onSourceError(base, std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
+ return;
+ } else if (res.noContent) {
+ observer->onSourceError(base, std::make_exception_ptr(std::runtime_error("unexpectedly empty TileJSON")));
+ } else {
+ Tileset newTileset;
+
+ // Create a new copy of the Tileset object that holds the base values we've parsed
+ // from the stylesheet. Then merge in the values parsed from the TileJSON we retrieved
+ // via the URL.
+ try {
+ newTileset = parseTileJSON(*res.data, url, type, tileSize);
+ } catch (...) {
+ observer->onSourceError(base, std::current_exception());
+ return;
+ }
+
+ // Check whether previous information specifies different tile
+ if (tileset.tiles != newTileset.tiles) {
+ // Tile URLs changed: force tiles to be reloaded.
+ invalidateTiles();
+
+ // Tile size changed: We need to recalculate the tiles we need to load because we
+ // might have to load tiles for a different zoom level
+ // This is done automatically when we trigger the onSourceLoaded observer below.
+
+ // Min/Max zoom changed: We need to recalculate what tiles to load, if we have tiles
+ // loaded that are outside the new zoom range
+ // This is done automatically when we trigger the onSourceLoaded observer below.
+
+ // Attribution changed: We need to notify the embedding application that this
+ // changed. See https://github.com/mapbox/mapbox-gl-native/issues/2723
+ // This is not yet implemented.
+
+ // Center/bounds changed: We're not using these values currently
+ }
+
+ tileset = newTileset;
+ loaded = true;
+
+ observer->onSourceLoaded(base);
+ }
+ });
+}
+
+Range<uint8_t> TileSourceImpl::getZoomRange() {
+ assert(loaded);
+ return tileset.zoomRange;
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/tile_source_impl.hpp b/src/mbgl/style/tile_source_impl.hpp
new file mode 100644
index 0000000000..8f420a15d5
--- /dev/null
+++ b/src/mbgl/style/tile_source_impl.hpp
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <mbgl/style/source_impl.hpp>
+#include <mbgl/util/tileset.hpp>
+#include <mbgl/util/variant.hpp>
+#include <mbgl/util/optional.hpp>
+
+namespace mbgl {
+
+class AsyncRequest;
+
+namespace style {
+
+/*
+ Shared implementation for VectorSource and RasterSource. Should eventually
+ be refactored to use composition rather than inheritance.
+*/
+class TileSourceImpl : public Source::Impl {
+public:
+ static Tileset parseTileJSON(const std::string& json, const std::string& sourceURL, SourceType, uint16_t tileSize);
+
+ TileSourceImpl(SourceType, std::string id, Source&,
+ variant<std::string, Tileset> urlOrTileset,
+ uint16_t tileSize);
+ ~TileSourceImpl() override;
+
+ void load(FileSource&) final;
+
+ uint16_t getTileSize() const final {
+ return tileSize;
+ }
+
+ const variant<std::string, Tileset>& getURLOrTileset() const {
+ return urlOrTileset;
+ }
+
+protected:
+ Range<uint8_t> getZoomRange() final;
+
+ const variant<std::string, Tileset> urlOrTileset;
+ const uint16_t tileSize;
+
+ Tileset tileset;
+ std::unique_ptr<AsyncRequest> req;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/types.cpp b/src/mbgl/style/types.cpp
new file mode 100644
index 0000000000..be0b217134
--- /dev/null
+++ b/src/mbgl/style/types.cpp
@@ -0,0 +1,92 @@
+#include <mbgl/style/types.hpp>
+#include <mbgl/util/enum.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+MBGL_DEFINE_ENUM(SourceType, {
+ { SourceType::Vector, "vector" },
+ { SourceType::Raster, "raster" },
+ { SourceType::GeoJSON, "geojson" },
+ { SourceType::Video, "video" },
+ { SourceType::Annotations, "annotations" },
+});
+
+MBGL_DEFINE_ENUM(VisibilityType, {
+ { VisibilityType::Visible, "visible" },
+ { VisibilityType::None, "none" },
+});
+
+MBGL_DEFINE_ENUM(TranslateAnchorType, {
+ { TranslateAnchorType::Map, "map" },
+ { TranslateAnchorType::Viewport, "viewport" },
+});
+
+MBGL_DEFINE_ENUM(RotateAnchorType, {
+ { RotateAnchorType::Map, "map" },
+ { RotateAnchorType::Viewport, "viewport" },
+});
+
+MBGL_DEFINE_ENUM(CirclePitchScaleType, {
+ { CirclePitchScaleType::Map, "map" },
+ { CirclePitchScaleType::Viewport, "viewport" },
+});
+
+MBGL_DEFINE_ENUM(LineCapType, {
+ { LineCapType::Round, "round" },
+ { LineCapType::Butt, "butt" },
+ { LineCapType::Square, "square" },
+});
+
+MBGL_DEFINE_ENUM(LineJoinType, {
+ { LineJoinType::Miter, "miter" },
+ { LineJoinType::Bevel, "bevel" },
+ { LineJoinType::Round, "round" },
+ { LineJoinType::FakeRound, "fakeround" },
+ { LineJoinType::FlipBevel, "flipbevel" },
+});
+
+MBGL_DEFINE_ENUM(SymbolPlacementType, {
+ { SymbolPlacementType::Point, "point" },
+ { SymbolPlacementType::Line, "line" },
+});
+
+MBGL_DEFINE_ENUM(TextAnchorType, {
+ { TextAnchorType::Center, "center" },
+ { TextAnchorType::Left, "left" },
+ { TextAnchorType::Right, "right" },
+ { TextAnchorType::Top, "top" },
+ { TextAnchorType::Bottom, "bottom" },
+ { TextAnchorType::TopLeft, "top-left" },
+ { TextAnchorType::TopRight, "top-right" },
+ { TextAnchorType::BottomLeft, "bottom-left" },
+ { TextAnchorType::BottomRight, "bottom-right" }
+});
+
+MBGL_DEFINE_ENUM(TextJustifyType, {
+ { TextJustifyType::Center, "center" },
+ { TextJustifyType::Left, "left" },
+ { TextJustifyType::Right, "right" },
+});
+
+MBGL_DEFINE_ENUM(TextTransformType, {
+ { TextTransformType::None, "none" },
+ { TextTransformType::Uppercase, "uppercase" },
+ { TextTransformType::Lowercase, "lowercase" },
+});
+
+MBGL_DEFINE_ENUM(AlignmentType, {
+ { AlignmentType::Map, "map" },
+ { AlignmentType::Viewport, "viewport" },
+ { AlignmentType::Undefined, "undefined" },
+});
+
+MBGL_DEFINE_ENUM(IconTextFitType, {
+ { IconTextFitType::None, "none" },
+ { IconTextFitType::Both, "both" },
+ { IconTextFitType::Width, "width" },
+ { IconTextFitType::Height, "height" },
+});
+
+} // namespace mbgl
diff --git a/src/mbgl/style/update_parameters.hpp b/src/mbgl/style/update_parameters.hpp
index 9faaa32d6f..bdae4f42b0 100644
--- a/src/mbgl/style/update_parameters.hpp
+++ b/src/mbgl/style/update_parameters.hpp
@@ -7,7 +7,6 @@ namespace mbgl {
class TransformState;
class Worker;
class FileSource;
-namespace gl { class TexturePool; }
class AnnotationManager;
namespace style {
@@ -22,18 +21,16 @@ public:
const TransformState& transformState_,
Worker& worker_,
FileSource& fileSource_,
- gl::TexturePool& texturePool_,
bool shouldReparsePartialTiles_,
const MapMode mode_,
AnnotationManager& annotationManager_,
Style& style_)
: pixelRatio(pixelRatio_),
debugOptions(debugOptions_),
- animationTime(animationTime_),
+ animationTime(std::move(animationTime_)),
transformState(transformState_),
worker(worker_),
fileSource(fileSource_),
- texturePool(texturePool_),
shouldReparsePartialTiles(shouldReparsePartialTiles_),
mode(mode_),
annotationManager(annotationManager_),
@@ -45,7 +42,6 @@ public:
const TransformState& transformState;
Worker& worker;
FileSource& fileSource;
- gl::TexturePool& texturePool;
bool shouldReparsePartialTiles;
const MapMode mode;
AnnotationManager& annotationManager;
diff --git a/src/mbgl/text/check_max_angle.hpp b/src/mbgl/text/check_max_angle.hpp
index 5e1ff6f049..008e70b5da 100644
--- a/src/mbgl/text/check_max_angle.hpp
+++ b/src/mbgl/text/check_max_angle.hpp
@@ -1,6 +1,6 @@
#pragma once
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
namespace mbgl {
diff --git a/src/mbgl/text/collision_feature.cpp b/src/mbgl/text/collision_feature.cpp
index 57a9da0440..74a41099ff 100644
--- a/src/mbgl/text/collision_feature.cpp
+++ b/src/mbgl/text/collision_feature.cpp
@@ -5,9 +5,9 @@ namespace mbgl {
CollisionFeature::CollisionFeature(const GeometryCoordinates &line, const Anchor &anchor,
const float top, const float bottom, const float left, const float right,
- const float boxScale, const float padding, const bool alongLine, const IndexedSubfeature& indexedFeature_,
+ const float boxScale, const float padding, const bool alongLine, IndexedSubfeature indexedFeature_,
const bool straight)
- : indexedFeature(indexedFeature_) {
+ : indexedFeature(std::move(indexedFeature_)) {
if (top == 0 && bottom == 0 && left == 0 && right == 0) return;
diff --git a/src/mbgl/text/collision_feature.hpp b/src/mbgl/text/collision_feature.hpp
index 0fcc083a19..5c0095bc6d 100644
--- a/src/mbgl/text/collision_feature.hpp
+++ b/src/mbgl/text/collision_feature.hpp
@@ -2,7 +2,7 @@
#include <mbgl/geometry/anchor.hpp>
#include <mbgl/text/shaping.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <vector>
@@ -10,8 +10,8 @@
namespace mbgl {
class CollisionBox {
public:
- explicit CollisionBox(const Point<float> &_anchor, float _x1, float _y1, float _x2, float _y2, float _maxScale) :
- anchor(_anchor), x1(_x1), y1(_y1), x2(_x2), y2(_y2), maxScale(_maxScale) {}
+ explicit CollisionBox(Point<float> _anchor, float _x1, float _y1, float _x2, float _y2, float _maxScale) :
+ anchor(std::move(_anchor)), x1(_x1), y1(_y1), x2(_x2), y2(_y2), maxScale(_maxScale) {}
// the box is centered around the anchor point
Point<float> anchor;
@@ -33,7 +33,7 @@ namespace mbgl {
class CollisionFeature {
public:
// for text
- inline explicit CollisionFeature(const GeometryCoordinates &line, const Anchor &anchor,
+ explicit CollisionFeature(const GeometryCoordinates &line, const Anchor &anchor,
const Shaping &shapedText,
const float boxScale, const float padding, const bool alongLine, const IndexedSubfeature& indexedFeature_)
: CollisionFeature(line, anchor,
@@ -41,7 +41,7 @@ namespace mbgl {
boxScale, padding, alongLine, indexedFeature_, false) {}
// for icons
- inline explicit CollisionFeature(const GeometryCoordinates &line, const Anchor &anchor,
+ explicit CollisionFeature(const GeometryCoordinates &line, const Anchor &anchor,
const PositionedIcon &shapedIcon,
const float boxScale, const float padding, const bool alongLine, const IndexedSubfeature& indexedFeature_)
: CollisionFeature(line, anchor,
@@ -51,7 +51,7 @@ namespace mbgl {
explicit CollisionFeature(const GeometryCoordinates &line, const Anchor &anchor,
const float top, const float bottom, const float left, const float right,
const float boxScale, const float padding, const bool alongLine,
- const IndexedSubfeature&, const bool straight);
+ IndexedSubfeature, const bool straight);
std::vector<CollisionBox> boxes;
diff --git a/src/mbgl/text/collision_tile.cpp b/src/mbgl/text/collision_tile.cpp
index e7824cde3c..982dff1688 100644
--- a/src/mbgl/text/collision_tile.cpp
+++ b/src/mbgl/text/collision_tile.cpp
@@ -9,7 +9,7 @@ namespace mbgl {
auto infinity = std::numeric_limits<float>::infinity();
-CollisionTile::CollisionTile(PlacementConfig config_) : config(config_),
+CollisionTile::CollisionTile(PlacementConfig config_) : config(std::move(config_)),
edges({{
// left
CollisionBox(Point<float>(0, 0), 0, -infinity, 0, infinity, infinity),
diff --git a/src/mbgl/text/get_anchors.cpp b/src/mbgl/text/get_anchors.cpp
index c55f238e52..ce45e05d9c 100644
--- a/src/mbgl/text/get_anchors.cpp
+++ b/src/mbgl/text/get_anchors.cpp
@@ -80,25 +80,25 @@ Anchors getAnchors(const GeometryCoordinates &line, float spacing,
const float angleWindowSize = (textLeft - textRight) != 0.0f ?
3.0f / 5.0f * glyphSize * boxScale :
0;
-
+
const float labelLength = fmax(textRight - textLeft, iconRight - iconLeft);
-
+
// Is the line continued from outside the tile boundary?
const bool continuedLine = (line[0].x == 0 || line[0].x == util::EXTENT || line[0].y == 0 || line[0].y == util::EXTENT);
-
+
// Is the label long, relative to the spacing?
// If so, adjust the spacing so there is always a minimum space of `spacing / 4` between label edges.
if (spacing - labelLength * boxScale < spacing / 4) {
spacing = labelLength * boxScale + spacing / 4;
}
-
+
// Offset the first anchor by:
// Either half the label length plus a fixed extra offset if the line is not continued
// Or half the spacing if the line is continued.
// For non-continued lines, add a bit of fixed extra offset to avoid collisions at T intersections.
const float fixedExtraOffset = glyphSize * 2;
-
+
const float offset = !continuedLine ?
std::fmod((labelLength / 2 + fixedExtraOffset) * boxScale * overscaling, spacing) :
std::fmod(spacing / 2 * overscaling, spacing);
diff --git a/src/mbgl/text/get_anchors.hpp b/src/mbgl/text/get_anchors.hpp
index 9a0a5a650c..b61f8fe0dc 100644
--- a/src/mbgl/text/get_anchors.hpp
+++ b/src/mbgl/text/get_anchors.hpp
@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/geometry/anchor.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/util/math.hpp>
namespace mbgl {
diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp
index b5891831d5..975dc4ad23 100644
--- a/src/mbgl/text/glyph.hpp
+++ b/src/mbgl/text/glyph.hpp
@@ -28,10 +28,9 @@ struct GlyphMetrics {
};
struct Glyph {
- inline explicit Glyph() : rect(0, 0, 0, 0), metrics() {}
- inline explicit Glyph(const Rect<uint16_t> &rect_,
- const GlyphMetrics &metrics_)
- : rect(rect_), metrics(metrics_) {}
+ explicit Glyph() : rect(0, 0, 0, 0), metrics() {}
+ explicit Glyph(Rect<uint16_t> rect_, GlyphMetrics metrics_)
+ : rect(std::move(rect_)), metrics(std::move(metrics_)) {}
operator bool() const {
return metrics || rect.hasArea();
@@ -45,7 +44,7 @@ typedef std::map<uint32_t, Glyph> GlyphPositions;
class PositionedGlyph {
public:
- inline explicit PositionedGlyph(uint32_t glyph_, float x_, float y_)
+ explicit PositionedGlyph(uint32_t glyph_, float x_, float y_)
: glyph(glyph_), x(x_), y(y_) {}
uint32_t glyph = 0;
@@ -55,8 +54,8 @@ public:
class Shaping {
public:
- inline explicit Shaping() : top(0), bottom(0), left(0), right(0) {}
- inline explicit Shaping(float x, float y, std::u32string text_)
+ explicit Shaping() : top(0), bottom(0), left(0), right(0) {}
+ explicit Shaping(float x, float y, std::u32string text_)
: text(std::move(text_)), top(y), bottom(y), left(x), right(x) {}
std::vector<PositionedGlyph> positionedGlyphs;
std::u32string text;
diff --git a/src/mbgl/text/glyph_pbf.cpp b/src/mbgl/text/glyph_pbf.cpp
index 9046464c5c..b4dac4ce01 100644
--- a/src/mbgl/text/glyph_pbf.cpp
+++ b/src/mbgl/text/glyph_pbf.cpp
@@ -53,7 +53,7 @@ void parseGlyphPBF(mbgl::GlyphSet& glyphSet, const std::string& data) {
}
}
- glyphSet.insert(glyph.id, glyph);
+ glyphSet.insert(glyph.id, std::move(glyph));
}
}
}
diff --git a/src/mbgl/text/glyph_pbf.hpp b/src/mbgl/text/glyph_pbf.hpp
index c238cbb5d7..85f4b62e6f 100644
--- a/src/mbgl/text/glyph_pbf.hpp
+++ b/src/mbgl/text/glyph_pbf.hpp
@@ -2,10 +2,10 @@
#include <mbgl/text/glyph.hpp>
#include <mbgl/text/glyph_store.hpp>
-#include <mbgl/util/atomic.hpp>
#include <mbgl/util/font_stack.hpp>
#include <mbgl/util/noncopyable.hpp>
+#include <atomic>
#include <functional>
#include <string>
#include <memory>
@@ -29,7 +29,7 @@ public:
}
private:
- util::Atomic<bool> parsed;
+ std::atomic<bool> parsed;
std::unique_ptr<AsyncRequest> req;
GlyphStoreObserver* observer = nullptr;
};
diff --git a/src/mbgl/text/glyph_set.cpp b/src/mbgl/text/glyph_set.cpp
index 8bd7e4ae03..0875a83850 100644
--- a/src/mbgl/text/glyph_set.cpp
+++ b/src/mbgl/text/glyph_set.cpp
@@ -6,11 +6,11 @@
namespace mbgl {
-void GlyphSet::insert(uint32_t id, const SDFGlyph &glyph) {
+void GlyphSet::insert(uint32_t id, SDFGlyph&& glyph) {
auto it = sdfs.find(id);
if (it == sdfs.end()) {
// Glyph doesn't exist yet.
- sdfs.emplace(id, glyph);
+ sdfs.emplace(id, std::move(glyph));
} else if (it->second.metrics == glyph.metrics) {
if (it->second.bitmap != glyph.bitmap) {
// The actual bitmap was updated; this is unsupported.
@@ -18,7 +18,7 @@ void GlyphSet::insert(uint32_t id, const SDFGlyph &glyph) {
}
// At least try to update it in case it's currently unsused.
// If it is already used; we won't attempt to update the glyph atlas texture.
- it->second.bitmap = glyph.bitmap;
+ it->second.bitmap = std::move(glyph.bitmap);
} else {
// The metrics were updated; this is unsupported.
Log::Warning(Event::Glyph, "Modified glyph has different metrics");
diff --git a/src/mbgl/text/glyph_set.hpp b/src/mbgl/text/glyph_set.hpp
index 77e2cb1c95..37ffdb070a 100644
--- a/src/mbgl/text/glyph_set.hpp
+++ b/src/mbgl/text/glyph_set.hpp
@@ -7,7 +7,7 @@ namespace mbgl {
class GlyphSet {
public:
- void insert(uint32_t id, const SDFGlyph &glyph);
+ void insert(uint32_t id, SDFGlyph&&);
const std::map<uint32_t, SDFGlyph> &getSDFs() const;
const Shaping getShaping(const std::u32string &string, float maxWidth, float lineHeight,
float horizontalAlign, float verticalAlign, float justify,
diff --git a/src/mbgl/text/placement_config.hpp b/src/mbgl/text/placement_config.hpp
index 75345b89e8..7e61cabc24 100644
--- a/src/mbgl/text/placement_config.hpp
+++ b/src/mbgl/text/placement_config.hpp
@@ -4,15 +4,15 @@ namespace mbgl {
class PlacementConfig {
public:
- inline PlacementConfig(float angle_ = 0, float pitch_ = 0, bool debug_ = false)
+ PlacementConfig(float angle_ = 0, float pitch_ = 0, bool debug_ = false)
: angle(angle_), pitch(pitch_), debug(debug_) {
}
- inline bool operator==(const PlacementConfig& rhs) const {
+ bool operator==(const PlacementConfig& rhs) const {
return angle == rhs.angle && pitch == rhs.pitch && debug == rhs.debug;
}
- inline bool operator!=(const PlacementConfig& rhs) const {
+ bool operator!=(const PlacementConfig& rhs) const {
return !operator==(rhs);
}
diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp
index ce320791c3..727b86f610 100644
--- a/src/mbgl/text/quads.cpp
+++ b/src/mbgl/text/quads.cpp
@@ -1,6 +1,6 @@
#include <mbgl/text/quads.hpp>
#include <mbgl/text/shaping.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/geometry/anchor.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/util/math.hpp>
@@ -15,7 +15,7 @@ const float globalMinScale = 0.5f; // underscale by 1 zoom level
SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
const GeometryCoordinates& line, const SymbolLayoutProperties& layout,
- const bool alongLine) {
+ const bool alongLine, const Shaping& shapedText) {
auto image = *(shapedIcon.image);
@@ -24,11 +24,43 @@ SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
auto right = left + image.pos.w / image.relativePixelRatio;
auto top = shapedIcon.top - border;
auto bottom = top + image.pos.h / image.relativePixelRatio;
- Point<float> tl{left, top};
- Point<float> tr{right, top};
- Point<float> br{right, bottom};
- Point<float> bl{left, bottom};
-
+ Point<float> tl;
+ Point<float> tr;
+ Point<float> br;
+ Point<float> bl;
+
+ if (layout.iconTextFit != IconTextFitType::None && shapedText) {
+ auto iconWidth = right - left;
+ auto iconHeight = bottom - top;
+ auto size = layout.textSize / 24.0f;
+ auto textLeft = shapedText.left * size;
+ auto textRight = shapedText.right * size;
+ auto textTop = shapedText.top * size;
+ auto textBottom = shapedText.bottom * size;
+ auto textWidth = textRight - textLeft;
+ auto textHeight = textBottom - textTop;;
+ auto padT = layout.iconTextFitPadding.value[0];
+ auto padR = layout.iconTextFitPadding.value[1];
+ auto padB = layout.iconTextFitPadding.value[2];
+ auto padL = layout.iconTextFitPadding.value[3];
+ auto offsetY = layout.iconTextFit == IconTextFitType::Width ? (textHeight - iconHeight) * 0.5 : 0;
+ auto offsetX = layout.iconTextFit == IconTextFitType::Height ? (textWidth - iconWidth) * 0.5 : 0;
+ auto width = layout.iconTextFit == IconTextFitType::Width || layout.iconTextFit == IconTextFitType::Both ? textWidth : iconWidth;
+ auto height = layout.iconTextFit == IconTextFitType::Height || layout.iconTextFit == IconTextFitType::Both ? textHeight : iconHeight;
+ left = textLeft + offsetX - padL;
+ top = textTop + offsetY - padT;
+ right = textLeft + offsetX + padR + width;
+ bottom = textTop + offsetY + padB + height;
+ tl = {left, top};
+ tr = {right, top};
+ br = {right, bottom};
+ bl = {left, bottom};
+ } else {
+ tl = {left, top};
+ tr = {right, top};
+ br = {right, bottom};
+ bl = {left, bottom};
+ }
float angle = layout.iconRotate * util::DEG2RAD;
if (alongLine) {
@@ -57,15 +89,15 @@ SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
}
SymbolQuads quads;
- quads.emplace_back(tl, tr, bl, br, image.pos, 0, anchor.point, globalMinScale, std::numeric_limits<float>::infinity());
+ quads.emplace_back(tl, tr, bl, br, image.pos, 0, 0, anchor.point, globalMinScale, std::numeric_limits<float>::infinity());
return quads;
}
struct GlyphInstance {
- explicit GlyphInstance(const Point<float> &anchorPoint_) : anchorPoint(anchorPoint_) {}
- explicit GlyphInstance(const Point<float> &anchorPoint_, float offset_, float minScale_, float maxScale_,
+ explicit GlyphInstance(Point<float> anchorPoint_) : anchorPoint(std::move(anchorPoint_)) {}
+ explicit GlyphInstance(Point<float> anchorPoint_, float offset_, float minScale_, float maxScale_,
float angle_)
- : anchorPoint(anchorPoint_), offset(offset_), minScale(minScale_), maxScale(maxScale_), angle(angle_) {}
+ : anchorPoint(std::move(anchorPoint_)), offset(offset_), minScale(minScale_), maxScale(maxScale_), angle(angle_) {}
const Point<float> anchorPoint;
const float offset = 0.0f;
@@ -102,8 +134,6 @@ void getSegmentGlyphs(std::back_insert_iterator<GlyphInstances> glyphs, Anchor &
float angle = std::atan2(end.y - newAnchorPoint.y, end.x - newAnchorPoint.x);
if (!forward)
angle += M_PI;
- if (upsideDown)
- angle += M_PI;
glyphs = GlyphInstance{
/* anchor */ newAnchorPoint,
@@ -188,12 +218,11 @@ SymbolQuads getGlyphQuads(Anchor& anchor, const Shaping& shapedText,
Point<float> tr = otr;
Point<float> bl = obl;
Point<float> br = obr;
- const float angle = instance.angle + textRotate;
- if (angle) {
+ if (textRotate) {
// Compute the transformation matrix.
- float angle_sin = std::sin(angle);
- float angle_cos = std::cos(angle);
+ float angle_sin = std::sin(textRotate);
+ float angle_cos = std::cos(textRotate);
std::array<float, 4> matrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}};
tl = util::matrixMultiply(matrix, tl);
@@ -205,8 +234,9 @@ SymbolQuads getGlyphQuads(Anchor& anchor, const Shaping& shapedText,
// Prevent label from extending past the end of the line
const float glyphMinScale = std::max(instance.minScale, anchor.scale);
- const float glyphAngle = std::fmod((anchor.angle + textRotate + instance.offset + 2 * M_PI), (2 * M_PI));
- quads.emplace_back(tl, tr, bl, br, rect, glyphAngle, instance.anchorPoint, glyphMinScale, instance.maxScale);
+ const float anchorAngle = std::fmod((anchor.angle + instance.offset + 2 * M_PI), (2 * M_PI));
+ const float glyphAngle = std::fmod((instance.angle + instance.offset + 2 * M_PI), (2 * M_PI));
+ quads.emplace_back(tl, tr, bl, br, rect, anchorAngle, glyphAngle, instance.anchorPoint, glyphMinScale, instance.maxScale);
}
diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp
index 0627647f4c..dd64af682a 100644
--- a/src/mbgl/text/quads.hpp
+++ b/src/mbgl/text/quads.hpp
@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/text/glyph.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <vector>
@@ -12,26 +12,26 @@ class PositionedIcon;
namespace style {
class SymbolLayoutProperties;
-}
+} // namespace style
struct SymbolQuad {
- explicit SymbolQuad(const Point<float> &tl_, const Point<float> &tr_,
- const Point<float> &bl_, const Point<float> &br_,
- const Rect<uint16_t> &tex_, float angle_, const Point<float> &anchorPoint_,
+ explicit SymbolQuad(Point<float> tl_, Point<float> tr_, Point<float> bl_, Point<float> br_,
+ Rect<uint16_t> tex_, float anchorAngle_, float glyphAngle_, Point<float> anchorPoint_,
float minScale_, float maxScale_)
- : tl(tl_),
- tr(tr_),
- bl(bl_),
- br(br_),
- tex(tex_),
- angle(angle_),
- anchorPoint(anchorPoint_),
+ : tl(std::move(tl_)),
+ tr(std::move(tr_)),
+ bl(std::move(bl_)),
+ br(std::move(br_)),
+ tex(std::move(tex_)),
+ anchorAngle(anchorAngle_),
+ glyphAngle(glyphAngle_),
+ anchorPoint(std::move(anchorPoint_)),
minScale(minScale_),
maxScale(maxScale_) {}
Point<float> tl, tr, bl, br;
Rect<uint16_t> tex;
- float angle;
+ float anchorAngle, glyphAngle;
Point<float> anchorPoint;
float minScale, maxScale;
};
@@ -40,7 +40,7 @@ typedef std::vector<SymbolQuad> SymbolQuads;
SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
const GeometryCoordinates& line, const style::SymbolLayoutProperties&,
- const bool alongLine);
+ const bool alongLine, const Shaping& shapedText);
SymbolQuads getGlyphQuads(Anchor& anchor, const Shaping& shapedText,
const float boxScale, const GeometryCoordinates& line, const style::SymbolLayoutProperties&,
diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp
index f81230acec..cd5e8105fd 100644
--- a/src/mbgl/text/shaping.hpp
+++ b/src/mbgl/text/shaping.hpp
@@ -11,12 +11,12 @@ struct SpriteAtlasElement;
namespace style {
class SymbolLayoutProperties;
-}
+} // namespace style
class PositionedIcon {
public:
- inline explicit PositionedIcon() {}
- inline explicit PositionedIcon(const SpriteAtlasElement& _image,
+ explicit PositionedIcon() {}
+ explicit PositionedIcon(const SpriteAtlasElement& _image,
float _top, float _bottom, float _left, float _right) :
image(_image), top(_top), bottom(_bottom), left(_left), right(_right) {}
diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp
index 90147ffd87..ab596bd9ba 100644
--- a/src/mbgl/tile/geojson_tile.cpp
+++ b/src/mbgl/tile/geojson_tile.cpp
@@ -1,12 +1,108 @@
#include <mbgl/tile/geojson_tile.hpp>
-#include <mbgl/storage/file_source.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
+#include <mbgl/style/update_parameters.hpp>
+
#include <mapbox/geojsonvt.hpp>
+#include <supercluster.hpp>
namespace mbgl {
+// Implements a simple in-memory Tile type that holds GeoJSON values. A GeoJSON tile can only have
+// one layer, and it is always returned regardless of which layer is requested.
+
+class GeoJSONTileFeature : public GeometryTileFeature {
+public:
+ GeoJSONTileFeature(FeatureType, GeometryCollection&&, PropertyMap&&);
+ FeatureType getType() const override;
+ optional<Value> getValue(const std::string&) const override;
+ PropertyMap getProperties() const override { return properties; }
+ GeometryCollection getGeometries() const override;
+
+private:
+ const FeatureType type;
+ const GeometryCollection geometries;
+ const PropertyMap properties;
+};
+
+class GeoJSONTileLayer : public GeometryTileLayer {
+public:
+ using Features = std::vector<std::shared_ptr<const GeoJSONTileFeature>>;
+
+ GeoJSONTileLayer(Features&&);
+ std::size_t featureCount() const override;
+ util::ptr<const GeometryTileFeature> getFeature(std::size_t) const override;
+ std::string getName() const override { return ""; };
+
+private:
+ const Features features;
+};
+
+class GeoJSONTileData : public GeometryTileData {
+public:
+ GeoJSONTileData(std::shared_ptr<GeoJSONTileLayer>);
+ util::ptr<GeometryTileLayer> getLayer(const std::string&) const override;
+
+private:
+ const std::shared_ptr<GeoJSONTileLayer> layer;
+};
+
+// Converts the geojsonvt::Tile to a a GeoJSONTile. They have a differing internal structure.
+std::unique_ptr<GeoJSONTileData> convertTile(const mapbox::geometry::feature_collection<int16_t>& features) {
+ std::shared_ptr<GeoJSONTileLayer> layer;
+
+ if (!features.empty()) {
+ std::vector<std::shared_ptr<const GeoJSONTileFeature>> convertedFeatures;
+
+ ToFeatureType toFeatureType;
+ ToGeometryCollection toGeometryCollection;
+
+ for (auto& feature : features) {
+ const FeatureType featureType = apply_visitor(toFeatureType, feature.geometry);
+
+ if (featureType == FeatureType::Unknown) {
+ continue;
+ }
+
+ GeometryCollection geometry = apply_visitor(toGeometryCollection, feature.geometry);
+
+ // https://github.com/mapbox/geojson-vt-cpp/issues/44
+ if (featureType == FeatureType::Polygon) {
+ geometry = fixupPolygons(geometry);
+ }
+
+ PropertyMap properties = feature.properties;
+
+ convertedFeatures.emplace_back(std::make_shared<GeoJSONTileFeature>(
+ featureType, std::move(geometry), std::move(properties)));
+ }
+
+ layer = std::make_unique<GeoJSONTileLayer>(std::move(convertedFeatures));
+ }
+
+ return std::make_unique<GeoJSONTileData>(layer);
+}
+
+GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID,
+ std::string sourceID_,
+ const style::UpdateParameters& parameters,
+ mapbox::geojsonvt::GeoJSONVT& geojsonvt)
+ : GeometryTile(overscaledTileID, sourceID_, parameters.style, parameters.mode) {
+ setData(convertTile(geojsonvt.getTile(id.canonical.z, id.canonical.x, id.canonical.y).features));
+}
+
+GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID,
+ std::string sourceID_,
+ const style::UpdateParameters& parameters,
+ mapbox::supercluster::Supercluster& supercluster)
+ : GeometryTile(overscaledTileID, sourceID_, parameters.style, parameters.mode) {
+ setData(convertTile(supercluster.getTile(id.canonical.z, id.canonical.x, id.canonical.y)));
+}
+
+void GeoJSONTile::setNecessity(Necessity) {}
+
GeoJSONTileFeature::GeoJSONTileFeature(FeatureType type_,
GeometryCollection&& geometries_,
- Feature::property_map&& properties_)
+ PropertyMap&& properties_)
: type(type_), geometries(std::move(geometries_)), properties(std::move(properties_)) {
}
@@ -37,105 +133,12 @@ util::ptr<const GeometryTileFeature> GeoJSONTileLayer::getFeature(std::size_t i)
return features[i];
}
-GeoJSONTile::GeoJSONTile(std::shared_ptr<GeoJSONTileLayer> layer_) : layer(std::move(layer_)) {
+GeoJSONTileData::GeoJSONTileData(std::shared_ptr<GeoJSONTileLayer> layer_) : layer(std::move(layer_)) {
}
-util::ptr<GeometryTileLayer> GeoJSONTile::getLayer(const std::string&) const {
+util::ptr<GeometryTileLayer> GeoJSONTileData::getLayer(const std::string&) const {
// We're ignoring the layer name because GeoJSON tiles only have one layer.
return layer;
}
-// Converts the geojsonvt::Tile to a a GeoJSONTile. They have a differing internal structure.
-std::unique_ptr<GeoJSONTile> convertTile(const mapbox::geojsonvt::Tile& tile) {
- std::shared_ptr<GeoJSONTileLayer> layer;
-
- if (tile) {
- std::vector<std::shared_ptr<const GeoJSONTileFeature>> features;
- GeometryCoordinates line;
-
- for (auto& feature : tile.features) {
- const FeatureType featureType =
- (feature.type == mapbox::geojsonvt::TileFeatureType::Point
- ? FeatureType::Point
- : (feature.type == mapbox::geojsonvt::TileFeatureType::LineString
- ? FeatureType::LineString
- : (feature.type == mapbox::geojsonvt::TileFeatureType::Polygon
- ? FeatureType::Polygon
- : FeatureType::Unknown)));
- if (featureType == FeatureType::Unknown) {
- continue;
- }
-
- GeometryCollection geometry;
-
- // Flatten the geometry; GeoJSONVT distinguishes between a Points array and Rings array
- // (Points = GeoJSON types Point, MultiPoint, LineString)
- // (Rings = GeoJSON types MultiLineString, Polygon, MultiPolygon)
- // However, in Mapbox GL, we use one structure for both types, and just have one outer
- // element for Points.
- if (feature.tileGeometry.is<mapbox::geojsonvt::TilePoints>()) {
- line.clear();
- for (auto& point : feature.tileGeometry.get<mapbox::geojsonvt::TilePoints>()) {
- line.emplace_back(point.x, point.y);
- }
- geometry.emplace_back(std::move(line));
- } else if (feature.tileGeometry.is<mapbox::geojsonvt::TileRings>()) {
- for (auto& ring : feature.tileGeometry.get<mapbox::geojsonvt::TileRings>()) {
- line.clear();
- for (auto& point : ring) {
- line.emplace_back(point.x, point.y);
- }
- geometry.emplace_back(std::move(line));
- }
- }
-
- // https://github.com/mapbox/geojson-vt-cpp/issues/44
- if (featureType == FeatureType::Polygon) {
- geometry = fixupPolygons(geometry);
- }
-
- Feature::property_map properties { feature.tags.begin(), feature.tags.end() };
-
- features.emplace_back(std::make_shared<GeoJSONTileFeature>(
- featureType, std::move(geometry), std::move(properties)));
- }
-
- layer = std::make_unique<GeoJSONTileLayer>(std::move(features));
- }
-
- return std::make_unique<GeoJSONTile>(layer);
-}
-
-GeoJSONTileMonitor::GeoJSONTileMonitor(mapbox::geojsonvt::GeoJSONVT* geojsonvt_,
- const OverscaledTileID& id)
- : tileID(id), geojsonvt(geojsonvt_) {
-}
-
-GeoJSONTileMonitor::~GeoJSONTileMonitor() = default;
-
-// A monitor can have its GeoJSONVT object swapped out (e.g. when loading a new GeoJSON file).
-// In that case, we're sending new notifications to all observers.
-void GeoJSONTileMonitor::setGeoJSONVT(mapbox::geojsonvt::GeoJSONVT* vt) {
- // Don't duplicate notifications in case of nil changes.
- if (geojsonvt != vt) {
- geojsonvt = vt;
- update();
- }
-}
-
-void GeoJSONTileMonitor::update() {
- if (geojsonvt) {
- auto tile = convertTile(
- geojsonvt->getTile(tileID.canonical.z, tileID.canonical.x, tileID.canonical.y));
- callback(nullptr, std::move(tile), {}, {});
- }
-}
-
-std::unique_ptr<AsyncRequest>
-GeoJSONTileMonitor::monitorTile(const GeometryTileMonitor::Callback& cb) {
- callback = cb;
- update();
- return nullptr;
-}
-
} // namespace mbgl
diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp
index 04ecbc9a24..422101b767 100644
--- a/src/mbgl/tile/geojson_tile.hpp
+++ b/src/mbgl/tile/geojson_tile.hpp
@@ -1,75 +1,38 @@
#pragma once
#include <mbgl/tile/geometry_tile.hpp>
-#include <mbgl/tile/tile_id.hpp>
-
-#include <unordered_map>
namespace mapbox {
+
namespace geojsonvt {
class GeoJSONVT;
} // namespace geojsonvt
-} // namespace mapbox
-namespace mbgl {
-
-// Implements a simple in-memory Tile type that holds GeoJSON values. A GeoJSON tile can only have
-// one layer, and it is always returned regardless of which layer is requested.
+namespace supercluster {
+class Supercluster;
+} // namespace supercluster
-class GeoJSONTileFeature : public GeometryTileFeature {
-public:
- GeoJSONTileFeature(FeatureType, GeometryCollection&&, Feature::property_map&&);
- FeatureType getType() const override;
- optional<Value> getValue(const std::string&) const override;
- Feature::property_map getProperties() const override { return properties; }
- GeometryCollection getGeometries() const override;
-
-private:
- const FeatureType type;
- const GeometryCollection geometries;
- const Feature::property_map properties;
-};
-
-class GeoJSONTileLayer : public GeometryTileLayer {
-public:
- using Features = std::vector<std::shared_ptr<const GeoJSONTileFeature>>;
+} // namespace mapbox
- GeoJSONTileLayer(Features&&);
- std::size_t featureCount() const override;
- util::ptr<const GeometryTileFeature> getFeature(std::size_t) const override;
- std::string getName() const override { return ""; };
+namespace mbgl {
-private:
- const Features features;
-};
+namespace style {
+class UpdateParameters;
+} // namespace style
class GeoJSONTile : public GeometryTile {
public:
- GeoJSONTile(std::shared_ptr<GeoJSONTileLayer>);
- util::ptr<GeometryTileLayer> getLayer(const std::string&) const override;
-
-private:
- const std::shared_ptr<GeoJSONTileLayer> layer;
-};
-
-class GeoJSONTileMonitor : public GeometryTileMonitor {
-public:
- GeoJSONTileMonitor(mapbox::geojsonvt::GeoJSONVT*, const OverscaledTileID&);
- virtual ~GeoJSONTileMonitor();
-
- std::unique_ptr<AsyncRequest> monitorTile(const GeometryTileMonitor::Callback&) override;
-
- void setGeoJSONVT(mapbox::geojsonvt::GeoJSONVT*);
+ GeoJSONTile(const OverscaledTileID&,
+ std::string sourceID,
+ const style::UpdateParameters&,
+ mapbox::geojsonvt::GeoJSONVT&);
-private:
- void update();
-
-public:
- const OverscaledTileID tileID;
+ GeoJSONTile(const OverscaledTileID&,
+ std::string sourceID,
+ const style::UpdateParameters&,
+ mapbox::supercluster::Supercluster&);
-private:
- mapbox::geojsonvt::GeoJSONVT* geojsonvt = nullptr;
- GeometryTileMonitor::Callback callback;
+ void setNecessity(Necessity) final;
};
} // namespace mbgl
diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp
index 1a74880377..daa358420b 100644
--- a/src/mbgl/tile/geometry_tile.cpp
+++ b/src/mbgl/tile/geometry_tile.cpp
@@ -1,218 +1,224 @@
#include <mbgl/tile/geometry_tile.hpp>
-#include <mbgl/tile/tile_id.hpp>
-
-#include <clipper/clipper.hpp>
+#include <mbgl/tile/tile_observer.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
+#include <mbgl/style/layer_impl.hpp>
+#include <mbgl/style/layers/background_layer.hpp>
+#include <mbgl/style/layers/custom_layer.hpp>
+#include <mbgl/util/worker.hpp>
+#include <mbgl/util/work_request.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/geometry/feature_index.hpp>
+#include <mbgl/text/collision_tile.hpp>
+#include <mbgl/map/transform_state.hpp>
namespace mbgl {
-static double signedArea(const GeometryCoordinates& ring) {
- double sum = 0;
-
- for (std::size_t i = 0, len = ring.size(), j = len - 1; i < len; j = i++) {
- const GeometryCoordinate& p1 = ring[i];
- const GeometryCoordinate& p2 = ring[j];
- sum += (p2.x - p1.x) * (p1.y + p2.y);
- }
+using namespace style;
+
+GeometryTile::GeometryTile(const OverscaledTileID& id_,
+ std::string sourceID_,
+ Style& style_,
+ const MapMode mode_)
+ : Tile(id_),
+ sourceID(std::move(sourceID_)),
+ style(style_),
+ worker(style_.workers),
+ tileWorker(id_,
+ *style_.spriteStore,
+ *style_.glyphAtlas,
+ *style_.glyphStore,
+ obsolete,
+ mode_) {
+}
- return sum;
+GeometryTile::~GeometryTile() {
+ cancel();
}
-static ClipperLib::Path toClipperPath(const GeometryCoordinates& ring) {
- ClipperLib::Path result;
- result.reserve(ring.size());
- for (const auto& p : ring) {
- result.emplace_back(p.x, p.y);
- }
- return result;
+void GeometryTile::setError(std::exception_ptr err) {
+ observer->onTileError(*this, err);
}
-static GeometryCoordinates fromClipperPath(const ClipperLib::Path& path) {
- GeometryCoordinates result;
- result.reserve(path.size() + 1);
-
- result.reserve(path.size());
- for (const auto& p : path) {
- using Coordinate = GeometryCoordinates::coordinate_type;
- assert(p.x >= std::numeric_limits<Coordinate>::min());
- assert(p.x <= std::numeric_limits<Coordinate>::max());
- assert(p.y >= std::numeric_limits<Coordinate>::min());
- assert(p.y <= std::numeric_limits<Coordinate>::max());
- result.emplace_back(Coordinate(p.x), Coordinate(p.y));
- }
-
- // Clipper does not repeat initial point, but our geometry model requires it.
- if (!result.empty()) {
- result.push_back(result.front());
+std::vector<std::unique_ptr<Layer>> GeometryTile::cloneStyleLayers() const {
+ std::vector<std::unique_ptr<Layer>> result;
+
+ for (const Layer* layer : style.getLayers()) {
+ // Avoid cloning and including irrelevant layers.
+ if (layer->is<BackgroundLayer>() ||
+ layer->is<CustomLayer>() ||
+ layer->baseImpl->source != sourceID ||
+ id.overscaledZ < std::floor(layer->baseImpl->minZoom) ||
+ id.overscaledZ >= std::ceil(layer->baseImpl->maxZoom) ||
+ layer->baseImpl->visibility == VisibilityType::None) {
+ continue;
+ }
+
+ result.push_back(layer->baseImpl->clone());
}
-
+
return result;
}
-static void processPolynodeBranch(ClipperLib::PolyNode* polynode, GeometryCollection& rings) {
- // Exterior ring.
- rings.push_back(fromClipperPath(polynode->Contour));
- assert(signedArea(rings.back()) > 0);
-
- // Interior rings.
- for (auto * ring : polynode->Childs) {
- rings.push_back(fromClipperPath(ring->Contour));
- assert(signedArea(rings.back()) < 0);
+void GeometryTile::setData(std::unique_ptr<GeometryTileData> data_) {
+ if (!data_) {
+ // This is a 404 response. We're treating these as empty tiles.
+ workRequest.reset();
+ availableData = DataAvailability::All;
+ buckets.clear();
+ redoPlacement();
+ observer->onTileLoaded(*this, true);
+ return;
}
- // PolyNodes may be nested in the case of a polygon inside a hole.
- for (auto * ring : polynode->Childs) {
- for (auto * subRing : ring->Childs) {
- processPolynodeBranch(subRing, rings);
- }
+ // Mark the tile as pending again if it was complete before to prevent signaling a complete
+ // state despite pending parse operations.
+ if (availableData == DataAvailability::All) {
+ availableData = DataAvailability::Some;
}
-}
-GeometryCollection fixupPolygons(const GeometryCollection& rings) {
- ClipperLib::Clipper clipper;
- clipper.StrictlySimple(true);
+ // Kick off a fresh parse of this tile. This happens when the tile is new, or
+ // when tile data changed. Replacing the workdRequest will cancel a pending work
+ // request in case there is one.
+ workRequest.reset();
+ workRequest = worker.parseGeometryTile(tileWorker, cloneStyleLayers(), std::move(data_), targetConfig, [this, config = targetConfig] (TileParseResult result) {
+ workRequest.reset();
- for (const auto& ring : rings) {
- clipper.AddPath(toClipperPath(ring), ClipperLib::ptSubject, true);
- }
+ if (result.is<TileParseResultData>()) {
+ auto& resultBuckets = result.get<TileParseResultData>();
+ availableData = resultBuckets.complete ? DataAvailability::All : DataAvailability::Some;
- ClipperLib::PolyTree polygons;
- clipper.Execute(ClipperLib::ctUnion, polygons, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
- clipper.Clear();
+ // Persist the configuration we just placed so that we can later check whether we need to
+ // place again in case the configuration has changed.
+ placedConfig = config;
- GeometryCollection result;
- for (auto * polynode : polygons.Childs) {
- processPolynodeBranch(polynode, result);
- }
- return result;
-}
+ // Move over all buckets we received in this parse request, potentially overwriting
+ // existing buckets in case we got a refresh parse.
+ buckets = std::move(resultBuckets.buckets);
-std::vector<GeometryCollection> classifyRings(const GeometryCollection& rings) {
- std::vector<GeometryCollection> polygons;
+ if (isComplete()) {
+ featureIndex = std::move(resultBuckets.featureIndex);
+ data = std::move(resultBuckets.tileData);
+ }
- std::size_t len = rings.size();
+ redoPlacement();
+ observer->onTileLoaded(*this, true);
+ } else {
+ availableData = DataAvailability::All;
+ observer->onTileError(*this, result.get<std::exception_ptr>());
+ }
+ });
+}
- if (len <= 1) {
- polygons.push_back(rings);
- return polygons;
+bool GeometryTile::parsePending() {
+ if (workRequest) {
+ // There's already parsing or placement going on.
+ return false;
}
- GeometryCollection polygon;
- int8_t ccw = 0;
+ workRequest.reset();
+ workRequest = worker.parsePendingGeometryTileLayers(tileWorker, targetConfig, [this, config = targetConfig] (TileParseResult result) {
+ workRequest.reset();
- for (std::size_t i = 0; i < len; i++) {
- double area = signedArea(rings[i]);
+ if (result.is<TileParseResultData>()) {
+ auto& resultBuckets = result.get<TileParseResultData>();
+ availableData = resultBuckets.complete ? DataAvailability::All : DataAvailability::Some;
- if (area == 0)
- continue;
+ // Move over all buckets we received in this parse request, potentially overwriting
+ // existing buckets in case we got a refresh parse.
+ for (auto& bucket : resultBuckets.buckets) {
+ buckets[bucket.first] = std::move(bucket.second);
+ }
- if (ccw == 0)
- ccw = (area < 0 ? -1 : 1);
+ // Persist the configuration we just placed so that we can later check whether we need to
+ // place again in case the configuration has changed.
+ placedConfig = config;
+
+ if (isComplete()) {
+ featureIndex = std::move(resultBuckets.featureIndex);
+ data = std::move(resultBuckets.tileData);
+ }
- if (ccw == (area < 0 ? -1 : 1) && !polygon.empty()) {
- polygons.push_back(polygon);
- polygon.clear();
+ redoPlacement();
+ observer->onTileLoaded(*this, false);
+ } else {
+ availableData = DataAvailability::All;
+ observer->onTileError(*this, result.get<std::exception_ptr>());
}
+ });
- polygon.push_back(rings[i]);
+ return true;
+}
+
+Bucket* GeometryTile::getBucket(const Layer& layer) {
+ const auto it = buckets.find(layer.baseImpl->bucketName());
+ if (it == buckets.end()) {
+ return nullptr;
}
- if (!polygon.empty())
- polygons.push_back(polygon);
+ assert(it->second);
+ return it->second.get();
+}
- return polygons;
+void GeometryTile::redoPlacement(const PlacementConfig newConfig) {
+ targetConfig = newConfig;
+ redoPlacement();
}
-void limitHoles(GeometryCollection& polygon, uint32_t maxHoles) {
- if (polygon.size() > 1 + maxHoles) {
- std::nth_element(polygon.begin() + 1,
- polygon.begin() + 1 + maxHoles,
- polygon.end(),
- [] (const auto& a, const auto& b) {
- return signedArea(a) > signedArea(b);
- });
- polygon.resize(1 + maxHoles);
+void GeometryTile::redoPlacement() {
+ // Don't start a new placement request when the current one hasn't completed yet, or when
+ // we are parsing buckets.
+ if (workRequest || targetConfig == placedConfig) {
+ return;
}
-}
-static Feature::geometry_type convertGeometry(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID) {
- const double size = util::EXTENT * std::pow(2, tileID.z);
- const double x0 = util::EXTENT * tileID.x;
- const double y0 = util::EXTENT * tileID.y;
-
- auto tileCoordinatesToLatLng = [&] (const Point<int16_t>& p) {
- double y2 = 180 - (p.y + y0) * 360 / size;
- return Point<double>(
- (p.x + x0) * 360 / size - 180,
- 360.0 / M_PI * std::atan(std::exp(y2 * M_PI / 180)) - 90.0
- );
- };
-
- GeometryCollection geometries = geometryTileFeature.getGeometries();
-
- switch (geometryTileFeature.getType()) {
- case FeatureType::Unknown: {
- assert(false);
- return Point<double>(NAN, NAN);
- }
+ workRequest = worker.redoPlacement(tileWorker, buckets, targetConfig, [this, config = targetConfig](std::unique_ptr<CollisionTile> collisionTile) {
+ workRequest.reset();
- case FeatureType::Point: {
- MultiPoint<double> multiPoint;
- for (const auto& p : geometries.at(0)) {
- multiPoint.push_back(tileCoordinatesToLatLng(p));
- }
- if (multiPoint.size() == 1) {
- return multiPoint[0];
- } else {
- return multiPoint;
- }
+ // Persist the configuration we just placed so that we can later check whether we need to
+ // place again in case the configuration has changed.
+ placedConfig = config;
+
+ for (auto& bucket : buckets) {
+ bucket.second->swapRenderData();
}
- case FeatureType::LineString: {
- MultiLineString<double> multiLineString;
- for (const auto& g : geometries) {
- LineString<double> lineString;
- for (const auto& p : g) {
- lineString.push_back(tileCoordinatesToLatLng(p));
- }
- multiLineString.push_back(std::move(lineString));
- }
- if (multiLineString.size() == 1) {
- return multiLineString[0];
- } else {
- return multiLineString;
- }
+ if (featureIndex) {
+ featureIndex->setCollisionTile(std::move(collisionTile));
}
- case FeatureType::Polygon: {
- MultiPolygon<double> multiPolygon;
- for (const auto& pg : classifyRings(geometries)) {
- Polygon<double> polygon;
- for (const auto& r : pg) {
- LinearRing<double> linearRing;
- for (const auto& p : r) {
- linearRing.push_back(tileCoordinatesToLatLng(p));
- }
- polygon.push_back(std::move(linearRing));
- }
- multiPolygon.push_back(std::move(polygon));
- }
- if (multiPolygon.size() == 1) {
- return multiPolygon[0];
- } else {
- return multiPolygon;
- }
+ // The target configuration could have changed since we started placement. In this case,
+ // we're starting another placement run.
+ if (placedConfig != targetConfig) {
+ redoPlacement();
+ } else {
+ observer->onNeedsRepaint();
}
- }
+ });
+}
- // Unreachable, but placate GCC.
- return Point<double>();
+void GeometryTile::queryRenderedFeatures(
+ std::unordered_map<std::string, std::vector<Feature>>& result,
+ const GeometryCoordinates& queryGeometry,
+ const TransformState& transformState,
+ const optional<std::vector<std::string>>& layerIDs) {
+
+ if (!featureIndex || !data) return;
+
+ featureIndex->query(result,
+ { queryGeometry },
+ transformState.getAngle(),
+ util::tileSize * id.overscaleFactor(),
+ std::pow(2, transformState.getZoom() - id.overscaledZ),
+ layerIDs,
+ *data,
+ id.canonical,
+ style);
}
-Feature convertFeature(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID) {
- Feature feature { convertGeometry(geometryTileFeature, tileID) };
- feature.properties = geometryTileFeature.getProperties();
- feature.id = geometryTileFeature.getID();
- return feature;
+void GeometryTile::cancel() {
+ obsolete = true;
+ workRequest.reset();
}
} // namespace mbgl
diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp
index 6904c922ba..891aba0432 100644
--- a/src/mbgl/tile/geometry_tile.hpp
+++ b/src/mbgl/tile/geometry_tile.hpp
@@ -1,104 +1,79 @@
#pragma once
-#include <mbgl/util/geometry.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/tile/tile_worker.hpp>
+#include <mbgl/text/placement_config.hpp>
#include <mbgl/util/feature.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/ptr.hpp>
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/optional.hpp>
-#include <mbgl/util/variant.hpp>
-#include <mbgl/util/constants.hpp>
-
-#include <cstdint>
-#include <string>
-#include <vector>
+
+#include <atomic>
+#include <memory>
#include <unordered_map>
-#include <functional>
+#include <vector>
namespace mbgl {
-enum class FeatureType : uint8_t {
- Unknown = 0,
- Point = 1,
- LineString = 2,
- Polygon = 3
-};
-
-class CanonicalTileID;
+class AsyncRequest;
+class GeometryTileData;
+class FeatureIndex;
-// Normalized vector tile coordinates.
-// Each geometry coordinate represents a point in a bidimensional space,
-// varying from -V...0...+V, where V is the maximum extent applicable.
-using GeometryCoordinate = Point<int16_t>;
+namespace style {
+class Style;
+class Layer;
+} // namespace style
-class GeometryCoordinates : public std::vector<GeometryCoordinate> {
+class GeometryTile : public Tile {
public:
- using coordinate_type = int16_t;
- using std::vector<GeometryCoordinate>::vector;
-};
+ GeometryTile(const OverscaledTileID&,
+ std::string sourceID,
+ style::Style&,
+ const MapMode);
-class GeometryCollection : public std::vector<GeometryCoordinates> {
-public:
- using coordinate_type = int16_t;
- using std::vector<GeometryCoordinates>::vector;
-};
+ ~GeometryTile() override;
-class GeometryTileFeature : private util::noncopyable {
-public:
- virtual ~GeometryTileFeature() = default;
- virtual FeatureType getType() const = 0;
- virtual optional<Value> getValue(const std::string& key) const = 0;
- virtual Feature::property_map getProperties() const { return Feature::property_map(); }
- virtual optional<uint64_t> getID() const { return {}; }
- virtual GeometryCollection getGeometries() const = 0;
-};
+ void setError(std::exception_ptr err);
+ void setData(std::unique_ptr<GeometryTileData>);
-class GeometryTileLayer : private util::noncopyable {
-public:
- virtual ~GeometryTileLayer() = default;
- virtual std::size_t featureCount() const = 0;
- virtual util::ptr<const GeometryTileFeature> getFeature(std::size_t) const = 0;
- virtual std::string getName() const = 0;
-};
+ Bucket* getBucket(const style::Layer&) override;
-class GeometryTile : private util::noncopyable {
-public:
- virtual ~GeometryTile() = default;
- virtual util::ptr<GeometryTileLayer> getLayer(const std::string&) const = 0;
-};
+ bool parsePending() override;
-class AsyncRequest;
+ void redoPlacement(PlacementConfig) override;
-class GeometryTileMonitor : private util::noncopyable {
-public:
- virtual ~GeometryTileMonitor() = default;
-
- using Callback = std::function<void (std::exception_ptr,
- std::unique_ptr<GeometryTile>,
- optional<Timestamp> modified,
- optional<Timestamp> expires)>;
- /*
- * Monitor the tile held by this object for changes. When the tile is loaded for the first time,
- * or updates, the callback is executed. If an error occurs, the first parameter will be set.
- * Otherwise it will be null. If there is no data for the requested tile, the second parameter
- * will be null.
- *
- * To cease monitoring, release the returned Request.
- */
- virtual std::unique_ptr<AsyncRequest> monitorTile(const Callback&) = 0;
-};
+ void queryRenderedFeatures(
+ std::unordered_map<std::string, std::vector<Feature>>& result,
+ const GeometryCoordinates& queryGeometry,
+ const TransformState&,
+ const optional<std::vector<std::string>>& layerIDs) override;
-// classifies an array of rings into polygons with outer rings and holes
-std::vector<GeometryCollection> classifyRings(const GeometryCollection&);
+ void cancel() override;
-// Truncate polygon to the largest `maxHoles` inner rings by area.
-void limitHoles(GeometryCollection&, uint32_t maxHoles);
+private:
+ std::vector<std::unique_ptr<style::Layer>> cloneStyleLayers() const;
+ void redoPlacement();
-// convert from GeometryTileFeature to Feature (eventually we should eliminate GeometryTileFeature)
-Feature convertFeature(const GeometryTileFeature&, const CanonicalTileID&);
+ const std::string sourceID;
+ style::Style& style;
+ Worker& worker;
+ TileWorker tileWorker;
-// Fix up possibly-non-V2-compliant polygon geometry using angus clipper.
-// The result is guaranteed to have correctly wound, strictly simple rings.
-GeometryCollection fixupPolygons(const GeometryCollection&);
+ std::unique_ptr<AsyncRequest> workRequest;
+
+ // Contains all the Bucket objects for the tile. Buckets are render
+ // objects and they get added by tile parsing operations.
+ std::unordered_map<std::string, std::unique_ptr<Bucket>> buckets;
+
+ std::unique_ptr<FeatureIndex> featureIndex;
+ std::unique_ptr<const GeometryTileData> data;
+
+ // Stores the placement configuration of the text that is currently placed on the screen.
+ PlacementConfig placedConfig;
+
+ // Stores the placement configuration of how the text should be placed. This isn't necessarily
+ // the one that is being displayed.
+ PlacementConfig targetConfig;
+
+ // Used to signal the worker that it should abandon parsing this tile as soon as possible.
+ std::atomic<bool> obsolete { false };
+};
} // namespace mbgl
diff --git a/src/mbgl/tile/geometry_tile_data.cpp b/src/mbgl/tile/geometry_tile_data.cpp
new file mode 100644
index 0000000000..2e465a6f65
--- /dev/null
+++ b/src/mbgl/tile/geometry_tile_data.cpp
@@ -0,0 +1,217 @@
+#include <mbgl/tile/geometry_tile_data.hpp>
+#include <mbgl/tile/tile_id.hpp>
+
+#include <clipper/clipper.hpp>
+
+namespace mbgl {
+
+static double signedArea(const GeometryCoordinates& ring) {
+ double sum = 0;
+
+ for (std::size_t i = 0, len = ring.size(), j = len - 1; i < len; j = i++) {
+ const GeometryCoordinate& p1 = ring[i];
+ const GeometryCoordinate& p2 = ring[j];
+ sum += (p2.x - p1.x) * (p1.y + p2.y);
+ }
+
+ return sum;
+}
+
+static ClipperLib::Path toClipperPath(const GeometryCoordinates& ring) {
+ ClipperLib::Path result;
+ result.reserve(ring.size());
+ for (const auto& p : ring) {
+ result.emplace_back(p.x, p.y);
+ }
+ return result;
+}
+
+static GeometryCoordinates fromClipperPath(const ClipperLib::Path& path) {
+ GeometryCoordinates result;
+ result.reserve(path.size() + 1);
+
+ for (const auto& p : path) {
+ using Coordinate = GeometryCoordinates::coordinate_type;
+ assert(p.x >= std::numeric_limits<Coordinate>::min());
+ assert(p.x <= std::numeric_limits<Coordinate>::max());
+ assert(p.y >= std::numeric_limits<Coordinate>::min());
+ assert(p.y <= std::numeric_limits<Coordinate>::max());
+ result.emplace_back(Coordinate(p.x), Coordinate(p.y));
+ }
+
+ // Clipper does not repeat initial point, but our geometry model requires it.
+ if (!result.empty()) {
+ result.push_back(result.front());
+ }
+
+ return result;
+}
+
+static void processPolynodeBranch(ClipperLib::PolyNode* polynode, GeometryCollection& rings) {
+ // Exterior ring.
+ rings.push_back(fromClipperPath(polynode->Contour));
+ assert(signedArea(rings.back()) > 0);
+
+ // Interior rings.
+ for (auto * ring : polynode->Childs) {
+ rings.push_back(fromClipperPath(ring->Contour));
+ assert(signedArea(rings.back()) < 0);
+ }
+
+ // PolyNodes may be nested in the case of a polygon inside a hole.
+ for (auto * ring : polynode->Childs) {
+ for (auto * subRing : ring->Childs) {
+ processPolynodeBranch(subRing, rings);
+ }
+ }
+}
+
+GeometryCollection fixupPolygons(const GeometryCollection& rings) {
+ ClipperLib::Clipper clipper;
+ clipper.StrictlySimple(true);
+
+ for (const auto& ring : rings) {
+ clipper.AddPath(toClipperPath(ring), ClipperLib::ptSubject, true);
+ }
+
+ ClipperLib::PolyTree polygons;
+ clipper.Execute(ClipperLib::ctUnion, polygons, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
+ clipper.Clear();
+
+ GeometryCollection result;
+ for (auto * polynode : polygons.Childs) {
+ processPolynodeBranch(polynode, result);
+ }
+ return result;
+}
+
+std::vector<GeometryCollection> classifyRings(const GeometryCollection& rings) {
+ std::vector<GeometryCollection> polygons;
+
+ std::size_t len = rings.size();
+
+ if (len <= 1) {
+ polygons.push_back(rings);
+ return polygons;
+ }
+
+ GeometryCollection polygon;
+ int8_t ccw = 0;
+
+ for (std::size_t i = 0; i < len; i++) {
+ double area = signedArea(rings[i]);
+
+ if (area == 0)
+ continue;
+
+ if (ccw == 0)
+ ccw = (area < 0 ? -1 : 1);
+
+ if (ccw == (area < 0 ? -1 : 1) && !polygon.empty()) {
+ polygons.push_back(polygon);
+ polygon.clear();
+ }
+
+ polygon.push_back(rings[i]);
+ }
+
+ if (!polygon.empty())
+ polygons.push_back(polygon);
+
+ return polygons;
+}
+
+void limitHoles(GeometryCollection& polygon, uint32_t maxHoles) {
+ if (polygon.size() > 1 + maxHoles) {
+ std::nth_element(polygon.begin() + 1,
+ polygon.begin() + 1 + maxHoles,
+ polygon.end(),
+ [] (const auto& a, const auto& b) {
+ return signedArea(a) > signedArea(b);
+ });
+ polygon.resize(1 + maxHoles);
+ }
+}
+
+static Feature::geometry_type convertGeometry(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID) {
+ const double size = util::EXTENT * std::pow(2, tileID.z);
+ const double x0 = util::EXTENT * tileID.x;
+ const double y0 = util::EXTENT * tileID.y;
+
+ auto tileCoordinatesToLatLng = [&] (const Point<int16_t>& p) {
+ double y2 = 180 - (p.y + y0) * 360 / size;
+ return Point<double>(
+ (p.x + x0) * 360 / size - 180,
+ 360.0 / M_PI * std::atan(std::exp(y2 * M_PI / 180)) - 90.0
+ );
+ };
+
+ GeometryCollection geometries = geometryTileFeature.getGeometries();
+
+ switch (geometryTileFeature.getType()) {
+ case FeatureType::Unknown: {
+ assert(false);
+ return Point<double>(NAN, NAN);
+ }
+
+ case FeatureType::Point: {
+ MultiPoint<double> multiPoint;
+ for (const auto& p : geometries.at(0)) {
+ multiPoint.push_back(tileCoordinatesToLatLng(p));
+ }
+ if (multiPoint.size() == 1) {
+ return multiPoint[0];
+ } else {
+ return multiPoint;
+ }
+ }
+
+ case FeatureType::LineString: {
+ MultiLineString<double> multiLineString;
+ for (const auto& g : geometries) {
+ LineString<double> lineString;
+ for (const auto& p : g) {
+ lineString.push_back(tileCoordinatesToLatLng(p));
+ }
+ multiLineString.push_back(std::move(lineString));
+ }
+ if (multiLineString.size() == 1) {
+ return multiLineString[0];
+ } else {
+ return multiLineString;
+ }
+ }
+
+ case FeatureType::Polygon: {
+ MultiPolygon<double> multiPolygon;
+ for (const auto& pg : classifyRings(geometries)) {
+ Polygon<double> polygon;
+ for (const auto& r : pg) {
+ LinearRing<double> linearRing;
+ for (const auto& p : r) {
+ linearRing.push_back(tileCoordinatesToLatLng(p));
+ }
+ polygon.push_back(std::move(linearRing));
+ }
+ multiPolygon.push_back(std::move(polygon));
+ }
+ if (multiPolygon.size() == 1) {
+ return multiPolygon[0];
+ } else {
+ return multiPolygon;
+ }
+ }
+ }
+
+ // Unreachable, but placate GCC.
+ return Point<double>();
+}
+
+Feature convertFeature(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID) {
+ Feature feature { convertGeometry(geometryTileFeature, tileID) };
+ feature.properties = geometryTileFeature.getProperties();
+ feature.id = geometryTileFeature.getID();
+ return feature;
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/tile/geometry_tile_data.hpp b/src/mbgl/tile/geometry_tile_data.hpp
new file mode 100644
index 0000000000..4055a80ecf
--- /dev/null
+++ b/src/mbgl/tile/geometry_tile_data.hpp
@@ -0,0 +1,143 @@
+#pragma once
+
+#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/feature.hpp>
+#include <mbgl/util/chrono.hpp>
+#include <mbgl/util/ptr.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/variant.hpp>
+#include <mbgl/util/constants.hpp>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+#include <unordered_map>
+#include <functional>
+#include <iostream>
+
+namespace mbgl {
+
+class CanonicalTileID;
+
+// Normalized vector tile coordinates.
+// Each geometry coordinate represents a point in a bidimensional space,
+// varying from -V...0...+V, where V is the maximum extent applicable.
+using GeometryCoordinate = Point<int16_t>;
+
+class GeometryCoordinates : public std::vector<GeometryCoordinate> {
+public:
+ using coordinate_type = int16_t;
+ using std::vector<GeometryCoordinate>::vector;
+};
+
+class GeometryCollection : public std::vector<GeometryCoordinates> {
+public:
+ using coordinate_type = int16_t;
+ using std::vector<GeometryCoordinates>::vector;
+};
+
+class GeometryTileFeature : private util::noncopyable {
+public:
+ virtual ~GeometryTileFeature() = default;
+ virtual FeatureType getType() const = 0;
+ virtual optional<Value> getValue(const std::string& key) const = 0;
+ virtual PropertyMap getProperties() const { return PropertyMap(); }
+ virtual optional<FeatureIdentifier> getID() const { return {}; }
+ virtual GeometryCollection getGeometries() const = 0;
+};
+
+class GeometryTileLayer : private util::noncopyable {
+public:
+ virtual ~GeometryTileLayer() = default;
+ virtual std::size_t featureCount() const = 0;
+ virtual util::ptr<const GeometryTileFeature> getFeature(std::size_t) const = 0;
+ virtual std::string getName() const = 0;
+};
+
+class GeometryTileData : private util::noncopyable {
+public:
+ virtual ~GeometryTileData() = default;
+ virtual util::ptr<GeometryTileLayer> getLayer(const std::string&) const = 0;
+};
+
+// classifies an array of rings into polygons with outer rings and holes
+std::vector<GeometryCollection> classifyRings(const GeometryCollection&);
+
+// Truncate polygon to the largest `maxHoles` inner rings by area.
+void limitHoles(GeometryCollection&, uint32_t maxHoles);
+
+// convert from GeometryTileFeature to Feature (eventually we should eliminate GeometryTileFeature)
+Feature convertFeature(const GeometryTileFeature&, const CanonicalTileID&);
+
+// Fix up possibly-non-V2-compliant polygon geometry using angus clipper.
+// The result is guaranteed to have correctly wound, strictly simple rings.
+GeometryCollection fixupPolygons(const GeometryCollection&);
+
+struct ToGeometryCollection {
+ GeometryCollection operator()(const mapbox::geometry::point<int16_t>& geom) const {
+ return { { geom } };
+ }
+ GeometryCollection operator()(const mapbox::geometry::multi_point<int16_t>& geom) const {
+ GeometryCoordinates coordinates;
+ coordinates.reserve(geom.size());
+ for (const auto& point : geom) {
+ coordinates.emplace_back(point);
+ }
+ return { coordinates };
+ }
+ GeometryCollection operator()(const mapbox::geometry::line_string<int16_t>& geom) const {
+ GeometryCoordinates coordinates;
+ coordinates.reserve(geom.size());
+ for (const auto& point : geom) {
+ coordinates.emplace_back(point);
+ }
+ return { coordinates };
+ }
+ GeometryCollection operator()(const mapbox::geometry::multi_line_string<int16_t>& geom) const {
+ GeometryCollection collection;
+ collection.reserve(geom.size());
+ for (const auto& ring : geom) {
+ GeometryCoordinates coordinates;
+ coordinates.reserve(ring.size());
+ for (const auto& point : ring) {
+ coordinates.emplace_back(point);
+ }
+ collection.push_back(std::move(coordinates));
+ }
+ return collection;
+ }
+ GeometryCollection operator()(const mapbox::geometry::polygon<int16_t>& geom) const {
+ GeometryCollection collection;
+ collection.reserve(geom.size());
+ for (const auto& ring : geom) {
+ GeometryCoordinates coordinates;
+ coordinates.reserve(ring.size());
+ for (const auto& point : ring) {
+ coordinates.emplace_back(point);
+ }
+ collection.push_back(std::move(coordinates));
+ }
+ return collection;
+ }
+ GeometryCollection operator()(const mapbox::geometry::multi_polygon<int16_t>& geom) const {
+ GeometryCollection collection;
+ for (auto& polygon : geom) {
+ for (auto& ring : polygon) {
+ GeometryCoordinates coordinates;
+ coordinates.reserve(ring.size());
+ for (auto& point : ring) {
+ coordinates.emplace_back(point);
+ }
+ collection.push_back(std::move(coordinates));
+ }
+ }
+ return collection;
+ }
+ GeometryCollection operator()(const mapbox::geometry::geometry_collection<int16_t>&) const {
+ GeometryCollection collection;
+ return collection;
+ }
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/tile/raster_tile.cpp b/src/mbgl/tile/raster_tile.cpp
new file mode 100644
index 0000000000..2460aac8f9
--- /dev/null
+++ b/src/mbgl/tile/raster_tile.cpp
@@ -0,0 +1,71 @@
+#include <mbgl/tile/raster_tile.hpp>
+#include <mbgl/tile/tile_observer.hpp>
+#include <mbgl/tile/tile_loader_impl.hpp>
+#include <mbgl/style/source.hpp>
+#include <mbgl/style/update_parameters.hpp>
+#include <mbgl/storage/resource.hpp>
+#include <mbgl/storage/response.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/util/worker.hpp>
+#include <mbgl/util/work_request.hpp>
+
+namespace mbgl {
+
+RasterTile::RasterTile(const OverscaledTileID& id_,
+ const style::UpdateParameters& parameters,
+ const Tileset& tileset)
+ : Tile(id_),
+ worker(parameters.worker),
+ loader(*this, id_, parameters, tileset) {
+}
+
+RasterTile::~RasterTile() = default;
+
+void RasterTile::setError(std::exception_ptr err) {
+ observer->onTileError(*this, err);
+}
+
+void RasterTile::setData(std::shared_ptr<const std::string> data,
+ optional<Timestamp> modified_,
+ optional<Timestamp> expires_) {
+ modified = modified_;
+ expires = expires_;
+
+ if (!data) {
+ // This is a 404 response. We're treating these as empty tiles.
+ workRequest.reset();
+ availableData = DataAvailability::All;
+ bucket.reset();
+ observer->onTileLoaded(*this, true);
+ return;
+ }
+
+ workRequest.reset();
+ workRequest = worker.parseRasterTile(std::make_unique<RasterBucket>(), data, [this] (RasterTileParseResult result) {
+ workRequest.reset();
+
+ availableData = DataAvailability::All;
+
+ if (result.is<std::unique_ptr<Bucket>>()) {
+ bucket = std::move(result.get<std::unique_ptr<Bucket>>());
+ observer->onTileLoaded(*this, true);
+ } else {
+ bucket.reset();
+ observer->onTileError(*this, result.get<std::exception_ptr>());
+ }
+ });
+}
+
+Bucket* RasterTile::getBucket(const style::Layer&) {
+ return bucket.get();
+}
+
+void RasterTile::setNecessity(Necessity necessity) {
+ loader.setNecessity(necessity);
+}
+
+void RasterTile::cancel() {
+ workRequest.reset();
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/tile/raster_tile.hpp b/src/mbgl/tile/raster_tile.hpp
new file mode 100644
index 0000000000..496edda6b3
--- /dev/null
+++ b/src/mbgl/tile/raster_tile.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/tile/tile_loader.hpp>
+#include <mbgl/renderer/raster_bucket.hpp>
+
+namespace mbgl {
+
+class AsyncRequest;
+class Tileset;
+
+namespace style {
+class Layer;
+class UpdateParameters;
+} // namespace style
+
+class RasterTile : public Tile {
+public:
+ RasterTile(const OverscaledTileID&,
+ const style::UpdateParameters&,
+ const Tileset&);
+ ~RasterTile() final;
+
+ void setNecessity(Necessity) final;
+
+ void setError(std::exception_ptr err);
+
+ void setData(std::shared_ptr<const std::string> data,
+ optional<Timestamp> modified_,
+ optional<Timestamp> expires_);
+
+ void cancel() override;
+ Bucket* getBucket(const style::Layer&) override;
+
+private:
+ Worker& worker;
+
+ TileLoader<RasterTile> loader;
+ std::unique_ptr<AsyncRequest> workRequest;
+
+ // Contains the Bucket object for the tile. Buckets are render
+ // objects and they get added by tile parsing operations.
+ std::unique_ptr<Bucket> bucket;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/tile/raster_tile_data.cpp b/src/mbgl/tile/raster_tile_data.cpp
deleted file mode 100644
index 420cb7055e..0000000000
--- a/src/mbgl/tile/raster_tile_data.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#include <mbgl/tile/raster_tile_data.hpp>
-#include <mbgl/style/source.hpp>
-#include <mbgl/storage/resource.hpp>
-#include <mbgl/storage/response.hpp>
-#include <mbgl/storage/file_source.hpp>
-#include <mbgl/util/worker.hpp>
-#include <mbgl/util/work_request.hpp>
-
-using namespace mbgl;
-
-RasterTileData::RasterTileData(const OverscaledTileID& id_,
- float pixelRatio,
- const std::string& urlTemplate,
- gl::TexturePool &texturePool_,
- Worker& worker_,
- FileSource& fileSource,
- const std::function<void(std::exception_ptr)>& callback)
- : TileData(id_),
- texturePool(texturePool_),
- worker(worker_) {
- const Resource resource =
- Resource::tile(urlTemplate, pixelRatio, id.canonical.x, id.canonical.y, id.canonical.z);
- req = fileSource.request(resource, [callback, this](Response res) {
- if (res.error) {
- callback(std::make_exception_ptr(std::runtime_error(res.error->message)));
- } else if (res.notModified) {
- modified = res.modified;
- expires = res.expires;
- } else if (res.noContent) {
- availableData = DataAvailability::All;
- modified = res.modified;
- expires = res.expires;
- workRequest.reset();
- bucket.reset();
- callback(nullptr);
- } else {
- modified = res.modified;
- expires = res.expires;
-
- workRequest.reset();
- workRequest = worker.parseRasterTile(std::make_unique<RasterBucket>(texturePool), res.data, [this, callback] (RasterTileParseResult result) {
- workRequest.reset();
-
- std::exception_ptr error;
- if (result.is<std::unique_ptr<Bucket>>()) {
- bucket = std::move(result.get<std::unique_ptr<Bucket>>());
- } else {
- error = result.get<std::exception_ptr>();
- bucket.reset();
- }
-
- availableData = DataAvailability::All;
-
- callback(error);
- });
- }
- });
-}
-
-RasterTileData::~RasterTileData() {
- cancel();
-}
-
-Bucket* RasterTileData::getBucket(const style::Layer&) {
- return bucket.get();
-}
-
-void RasterTileData::cancel() {
- req = nullptr;
- workRequest.reset();
-}
diff --git a/src/mbgl/tile/raster_tile_data.hpp b/src/mbgl/tile/raster_tile_data.hpp
deleted file mode 100644
index 62d21d28c4..0000000000
--- a/src/mbgl/tile/raster_tile_data.hpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#pragma once
-
-#include <mbgl/tile/tile_data.hpp>
-#include <mbgl/renderer/raster_bucket.hpp>
-
-namespace mbgl {
-
-class FileSource;
-class AsyncRequest;
-
-namespace gl { class TexturePool; }
-
-namespace style {
-class Layer;
-}
-
-class RasterTileData : public TileData {
-public:
- RasterTileData(const OverscaledTileID&,
- float pixelRatio,
- const std::string& urlTemplate,
- gl::TexturePool&,
- Worker&,
- FileSource&,
- const std::function<void(std::exception_ptr)>& callback);
- ~RasterTileData();
-
- void cancel() override;
- Bucket* getBucket(const style::Layer&) override;
-
-private:
- gl::TexturePool& texturePool;
- Worker& worker;
- std::unique_ptr<AsyncRequest> req;
- std::unique_ptr<Bucket> bucket;
- std::unique_ptr<AsyncRequest> workRequest;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp
index a1d36421a4..6595c314ee 100644
--- a/src/mbgl/tile/tile.cpp
+++ b/src/mbgl/tile/tile.cpp
@@ -1,3 +1,36 @@
#include <mbgl/tile/tile.hpp>
+#include <mbgl/tile/tile_observer.hpp>
+#include <mbgl/renderer/debug_bucket.hpp>
+#include <mbgl/util/string.hpp>
-using namespace mbgl;
+namespace mbgl {
+
+static TileObserver nullObserver;
+
+Tile::Tile(OverscaledTileID id_) : id(std::move(id_)), observer(&nullObserver) {
+}
+
+Tile::~Tile() = default;
+
+void Tile::setObserver(TileObserver* observer_) {
+ observer = observer_;
+}
+
+void Tile::setTriedOptional() {
+ triedOptional = true;
+ observer->onNeedsRepaint();
+}
+
+void Tile::dumpDebugLogs() const {
+ Log::Info(Event::General, "Tile::id: %s", util::toString(id).c_str());
+ Log::Info(Event::General, "Tile::renderable: %s", isRenderable() ? "yes" : "no");
+ Log::Info(Event::General, "Tile::complete: %s", isComplete() ? "yes" : "no");
+}
+
+void Tile::queryRenderedFeatures(
+ std::unordered_map<std::string, std::vector<Feature>>&,
+ const GeometryCoordinates&,
+ const TransformState&,
+ const optional<std::vector<std::string>>&) {}
+
+} // namespace mbgl
diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp
index 1e35e78735..65f3aaa245 100644
--- a/src/mbgl/tile/tile.hpp
+++ b/src/mbgl/tile/tile.hpp
@@ -1,28 +1,111 @@
#pragma once
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/chrono.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/feature.hpp>
#include <mbgl/tile/tile_id.hpp>
-#include <mbgl/util/mat4.hpp>
-#include <mbgl/util/ptr.hpp>
-#include <mbgl/util/clip_id.hpp>
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/text/placement_config.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
+#include <mbgl/storage/resource.hpp>
+
+#include <string>
+#include <memory>
+#include <functional>
+#include <unordered_map>
namespace mbgl {
-class TileData;
+class Worker;
+class DebugBucket;
+class TransformState;
+class TileObserver;
+
+namespace style {
+class Layer;
+} // namespace style
-class Tile {
+class Tile : private util::noncopyable {
public:
- Tile(const UnwrappedTileID& id_, TileData& data_) : id(id_), data(data_) {
+ Tile(OverscaledTileID);
+ virtual ~Tile();
+
+ void setObserver(TileObserver* observer);
+
+ // Tiles can have two states: optional or required.
+ // - optional means that only low-cost actions should be taken to obtain the data
+ // (e.g. load from cache, but accept stale data)
+ // - required means that every effort should be taken to obtain the data (e.g. load
+ // from internet and keep the data fresh if it expires)
+ using Necessity = Resource::Necessity;
+
+ virtual void setNecessity(Necessity) = 0;
+
+ // Mark this tile as no longer needed and cancel any pending work.
+ virtual void cancel() = 0;
+
+ virtual Bucket* getBucket(const style::Layer&) = 0;
+
+ virtual bool parsePending() { return true; }
+ virtual void redoPlacement(PlacementConfig) {}
+
+ virtual void queryRenderedFeatures(
+ std::unordered_map<std::string, std::vector<Feature>>& result,
+ const GeometryCoordinates& queryGeometry,
+ const TransformState&,
+ const optional<std::vector<std::string>>& layerIDs);
+
+ void setTriedOptional();
+
+ // Returns true when the tile source has received a first response, regardless of whether a load
+ // error occurred or actual data was loaded.
+ bool hasTriedOptional() const {
+ return triedOptional;
}
- Tile(const Tile&) = delete;
- Tile(Tile&&) = default;
- Tile& operator=(const Tile&) = delete;
- Tile& operator=(Tile&&) = default;
+ // Tile data considered "Renderable" can be used for rendering. Data in
+ // partial state is still waiting for network resources but can also
+ // be rendered, although layers will be missing.
+ bool isRenderable() const {
+ return availableData != DataAvailability::None;
+ }
+
+ bool isComplete() const {
+ return availableData == DataAvailability::All;
+ }
+ bool isIncomplete() const {
+ return availableData == DataAvailability::Some;
+ }
+
+ void dumpDebugLogs() const;
+
+ const OverscaledTileID id;
+ optional<Timestamp> modified;
+ optional<Timestamp> expires;
+
+ // Contains the tile ID string for painting debug information.
+ std::unique_ptr<DebugBucket> debugBucket;
+
+protected:
+ bool triedOptional = false;
+
+ enum class DataAvailability : uint8_t {
+ // Still waiting for data to load or parse.
+ None,
+
+ // Tile is partially parsed, some buckets are still waiting for dependencies
+ // to arrive, but it is good for rendering. Partial tiles can also be re-parsed,
+ // but might remain in the same state if dependencies are still missing.
+ Some,
+
+ // Tile is fully parsed, and all buckets are available if they exist.
+ All,
+ };
+
+ DataAvailability availableData = DataAvailability::None;
- const UnwrappedTileID id;
- TileData& data;
- ClipID clip;
- mat4 matrix;
+ TileObserver* observer = nullptr;
};
} // namespace mbgl
diff --git a/src/mbgl/tile/tile_cache.cpp b/src/mbgl/tile/tile_cache.cpp
index e012ef0b7e..3fafb1259c 100644
--- a/src/mbgl/tile/tile_cache.cpp
+++ b/src/mbgl/tile/tile_cache.cpp
@@ -1,5 +1,5 @@
#include <mbgl/tile/tile_cache.hpp>
-#include <mbgl/tile/tile_data.hpp>
+#include <mbgl/tile/tile.hpp>
#include <cassert>
@@ -17,42 +17,42 @@ void TileCache::setSize(size_t size_) {
assert(orderedKeys.size() <= size);
}
-void TileCache::add(const OverscaledTileID& key, std::unique_ptr<TileData> data) {
- if (!data->isRenderable() || !size) {
+void TileCache::add(const OverscaledTileID& key, std::unique_ptr<Tile> tile) {
+ if (!tile->isRenderable() || !size) {
return;
}
- // insert new or query existing data
- if (tiles.emplace(key, std::move(data)).second) {
- // remove existing data key
+ // insert new or query existing tile
+ if (tiles.emplace(key, std::move(tile)).second) {
+ // remove existing tile key
orderedKeys.remove(key);
}
- // (re-)insert data key as newest
+ // (re-)insert tile key as newest
orderedKeys.push_back(key);
- // purge oldest key/data if necessary
+ // purge oldest key/tile if necessary
if (orderedKeys.size() > size) {
get(orderedKeys.front());
}
assert(orderedKeys.size() <= size);
-};
+}
-std::unique_ptr<TileData> TileCache::get(const OverscaledTileID& key) {
+std::unique_ptr<Tile> TileCache::get(const OverscaledTileID& key) {
- std::unique_ptr<TileData> data;
+ std::unique_ptr<Tile> tile;
auto it = tiles.find(key);
if (it != tiles.end()) {
- data = std::move(it->second);
+ tile = std::move(it->second);
tiles.erase(it);
orderedKeys.remove(key);
- assert(data->isRenderable());
+ assert(tile->isRenderable());
}
- return data;
-};
+ return tile;
+}
bool TileCache::has(const OverscaledTileID& key) {
return tiles.find(key) != tiles.end();
diff --git a/src/mbgl/tile/tile_cache.hpp b/src/mbgl/tile/tile_cache.hpp
index edaa6bd680..80fe98a20c 100644
--- a/src/mbgl/tile/tile_cache.hpp
+++ b/src/mbgl/tile/tile_cache.hpp
@@ -8,7 +8,7 @@
namespace mbgl {
-class TileData;
+class Tile;
class TileCache {
public:
@@ -16,13 +16,13 @@ public:
void setSize(size_t);
size_t getSize() const { return size; };
- void add(const OverscaledTileID& key, std::unique_ptr<TileData> data);
- std::unique_ptr<TileData> get(const OverscaledTileID& key);
+ void add(const OverscaledTileID& key, std::unique_ptr<Tile> data);
+ std::unique_ptr<Tile> get(const OverscaledTileID& key);
bool has(const OverscaledTileID& key);
void clear();
private:
- std::map<OverscaledTileID, std::unique_ptr<TileData>> tiles;
+ std::map<OverscaledTileID, std::unique_ptr<Tile>> tiles;
std::list<OverscaledTileID> orderedKeys;
size_t size;
diff --git a/src/mbgl/tile/tile_data.cpp b/src/mbgl/tile/tile_data.cpp
deleted file mode 100644
index e23ae2a727..0000000000
--- a/src/mbgl/tile/tile_data.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <mbgl/tile/tile_data.hpp>
-#include <mbgl/renderer/debug_bucket.hpp>
-#include <mbgl/util/string.hpp>
-
-namespace mbgl {
-
-TileData::TileData(const OverscaledTileID& id_)
- : id(id_) {
-}
-
-TileData::~TileData() = default;
-
-void TileData::dumpDebugLogs() const {
- Log::Info(Event::General, "TileData::id: %s", util::toString(id).c_str());
- Log::Info(Event::General, "TileData::renderable: %s", isRenderable() ? "yes" : "no");
- Log::Info(Event::General, "TileData::complete: %s", isComplete() ? "yes" : "no");
-}
-
-void TileData::queryRenderedFeatures(
- std::unordered_map<std::string, std::vector<Feature>>&,
- const GeometryCoordinates&,
- const TransformState&,
- const optional<std::vector<std::string>>&) {}
-
-} // namespace mbgl
diff --git a/src/mbgl/tile/tile_data.hpp b/src/mbgl/tile/tile_data.hpp
deleted file mode 100644
index 5b6583faf8..0000000000
--- a/src/mbgl/tile/tile_data.hpp
+++ /dev/null
@@ -1,87 +0,0 @@
-#pragma once
-
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/optional.hpp>
-#include <mbgl/util/feature.hpp>
-#include <mbgl/tile/tile_id.hpp>
-#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/text/placement_config.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
-
-#include <string>
-#include <memory>
-#include <functional>
-#include <unordered_map>
-
-namespace mbgl {
-
-class Worker;
-class DebugBucket;
-class TransformState;
-
-namespace style {
-class Layer;
-}
-
-class TileData : private util::noncopyable {
-public:
- TileData(const OverscaledTileID&);
- virtual ~TileData();
-
- // Mark this tile as no longer needed and cancel any pending work.
- virtual void cancel() = 0;
-
- virtual Bucket* getBucket(const style::Layer&) = 0;
-
- virtual bool parsePending(std::function<void (std::exception_ptr)>) { return true; }
- virtual void redoPlacement(PlacementConfig, const std::function<void()>&) {}
- virtual void redoPlacement(const std::function<void()>&) {}
-
- virtual void queryRenderedFeatures(
- std::unordered_map<std::string, std::vector<Feature>>& result,
- const GeometryCoordinates& queryGeometry,
- const TransformState&,
- const optional<std::vector<std::string>>& layerIDs);
-
- // Tile data considered "Renderable" can be used for rendering. Data in
- // partial state is still waiting for network resources but can also
- // be rendered, although layers will be missing.
- bool isRenderable() const {
- return availableData != DataAvailability::None;
- }
-
- bool isComplete() const {
- return availableData == DataAvailability::All;
- }
- bool isIncomplete() const {
- return availableData == DataAvailability::Some;
- }
-
- void dumpDebugLogs() const;
-
- const OverscaledTileID id;
- optional<Timestamp> modified;
- optional<Timestamp> expires;
-
- // Contains the tile ID string for painting debug information.
- std::unique_ptr<DebugBucket> debugBucket;
-
-protected:
- enum class DataAvailability : uint8_t {
- // Still waiting for data to load or parse.
- None,
-
- // TileData is partially parsed, some buckets are still waiting for dependencies
- // to arrive, but it is good for rendering. Partial tiles can also be re-parsed,
- // but might remain in the same state if dependencies are still missing.
- Some,
-
- // TileData is fully parsed, and all buckets are available if they exist.
- All,
- };
-
- DataAvailability availableData = DataAvailability::None;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/tile/tile_id.hpp b/src/mbgl/tile/tile_id.hpp
index f9afdfa529..f561db9a4d 100644
--- a/src/mbgl/tile/tile_id.hpp
+++ b/src/mbgl/tile/tile_id.hpp
@@ -45,8 +45,7 @@ std::string toString(const CanonicalTileID&);
// z/x/y describe the
class OverscaledTileID {
public:
- OverscaledTileID(uint8_t overscaledZ, const CanonicalTileID&);
- OverscaledTileID(uint8_t overscaledZ, CanonicalTileID&&);
+ OverscaledTileID(uint8_t overscaledZ, CanonicalTileID);
OverscaledTileID(uint8_t overscaledZ, uint8_t z, uint32_t x, uint32_t y);
OverscaledTileID(uint8_t z, uint32_t x, uint32_t y);
explicit OverscaledTileID(const CanonicalTileID&);
@@ -75,8 +74,7 @@ std::string toString(const OverscaledTileID&);
class UnwrappedTileID {
public:
UnwrappedTileID(uint8_t z, int64_t x, int64_t y);
- UnwrappedTileID(int16_t wrap, const CanonicalTileID&);
- UnwrappedTileID(int16_t wrap, CanonicalTileID&&);
+ UnwrappedTileID(int16_t wrap, CanonicalTileID);
bool operator==(const UnwrappedTileID&) const;
bool operator!=(const UnwrappedTileID&) const;
bool operator<(const UnwrappedTileID&) const;
@@ -143,13 +141,8 @@ inline std::array<CanonicalTileID, 4> CanonicalTileID::children() const {
} };
}
-inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, const CanonicalTileID& canonical_)
- : overscaledZ(overscaledZ_), canonical(canonical_) {
- assert(overscaledZ >= canonical.z);
-}
-
-inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, CanonicalTileID&& canonical_)
- : overscaledZ(overscaledZ_), canonical(std::forward<CanonicalTileID>(canonical_)) {
+inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, CanonicalTileID canonical_)
+ : overscaledZ(overscaledZ_), canonical(std::move(canonical_)) {
assert(overscaledZ >= canonical.z);
}
@@ -216,12 +209,8 @@ inline UnwrappedTileID::UnwrappedTileID(uint8_t z_, int64_t x_, int64_t y_)
y_ < 0 ? 0 : std::min(static_cast<uint32_t>(y_), static_cast<uint32_t>(1ull << z_) - 1)) {
}
-inline UnwrappedTileID::UnwrappedTileID(int16_t wrap_, const CanonicalTileID& canonical_)
- : wrap(wrap_), canonical(canonical_) {
-}
-
-inline UnwrappedTileID::UnwrappedTileID(int16_t wrap_, CanonicalTileID&& canonical_)
- : wrap(wrap_), canonical(std::forward<CanonicalTileID>(canonical_)) {
+inline UnwrappedTileID::UnwrappedTileID(int16_t wrap_, CanonicalTileID canonical_)
+ : wrap(wrap_), canonical(std::move(canonical_)) {
}
inline bool UnwrappedTileID::operator==(const UnwrappedTileID& rhs) const {
diff --git a/src/mbgl/tile/tile_loader.hpp b/src/mbgl/tile/tile_loader.hpp
new file mode 100644
index 0000000000..0d64f647d7
--- /dev/null
+++ b/src/mbgl/tile/tile_loader.hpp
@@ -0,0 +1,62 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/storage/resource.hpp>
+#include <mbgl/tile/tile.hpp>
+
+namespace mbgl {
+
+class FileSource;
+class AsyncRequest;
+class Response;
+class Tileset;
+
+namespace style {
+class UpdateParameters;
+} // namespace style
+
+template <typename T>
+class TileLoader : private util::noncopyable {
+public:
+ TileLoader(T&,
+ const OverscaledTileID&,
+ const style::UpdateParameters&,
+ const Tileset&);
+ ~TileLoader();
+
+ using Necessity = Resource::Necessity;
+
+ void setNecessity(Necessity newNecessity) {
+ if (newNecessity != necessity) {
+ necessity = newNecessity;
+ if (necessity == Necessity::Required) {
+ makeRequired();
+ } else {
+ makeOptional();
+ }
+ }
+ }
+
+private:
+ // called when the tile is one of the ideal tiles that we want to show definitely. the tile source
+ // should try to make every effort (e.g. fetch from internet, or revalidate existing resources).
+ void makeRequired();
+
+ // called when the zoom level no longer corresponds to the displayed one, but
+ // we're still interested in retaining the tile, e.g. for backfill.
+ // subclassed TileSources should cancel actions they are taking to provide
+ // an up-to-date version or load new data
+ void makeOptional();
+
+ void loadOptional();
+ void loadedData(const Response&);
+ void loadRequired();
+
+ T& tile;
+ Necessity necessity;
+ Resource resource;
+ FileSource& fileSource;
+ std::unique_ptr<AsyncRequest> request;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/tile/tile_loader_impl.hpp b/src/mbgl/tile/tile_loader_impl.hpp
new file mode 100644
index 0000000000..b987d6ec65
--- /dev/null
+++ b/src/mbgl/tile/tile_loader_impl.hpp
@@ -0,0 +1,113 @@
+#pragma once
+
+#include <mbgl/tile/tile_loader.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/style/update_parameters.hpp>
+#include <mbgl/util/tileset.hpp>
+
+#include <cassert>
+
+namespace mbgl {
+
+template <typename T>
+TileLoader<T>::TileLoader(T& tile_,
+ const OverscaledTileID& id,
+ const style::UpdateParameters& parameters,
+ const Tileset& tileset)
+ : tile(tile_),
+ necessity(Necessity::Optional),
+ resource(Resource::tile(
+ tileset.tiles.at(0),
+ parameters.pixelRatio,
+ id.canonical.x,
+ id.canonical.y,
+ id.canonical.z)),
+ fileSource(parameters.fileSource) {
+ assert(!request);
+ if (fileSource.supportsOptionalRequests()) {
+ // When supported, the first request is always optional, even if the TileLoader
+ // is marked as required. That way, we can let the first optional request continue
+ // to load when the TileLoader is later changed from required to optional. If we
+ // started out with a required request, we'd have to cancel everything, including the
+ // initial optional part of the request.
+ loadOptional();
+ } else {
+ // When the FileSource doesn't support optional requests, we do nothing until the
+ // data is definitely required.
+ if (necessity == Necessity::Required) {
+ loadRequired();
+ } else {
+ // We're using this field to check whether the pending request is optional or required.
+ resource.necessity = Resource::Optional;
+ }
+ }
+}
+
+template <typename T>
+TileLoader<T>::~TileLoader() = default;
+
+template <typename T>
+void TileLoader<T>::loadOptional() {
+ assert(!request);
+
+ resource.necessity = Resource::Optional;
+ request = fileSource.request(resource, [this](Response res) {
+ request.reset();
+
+ tile.setTriedOptional();
+
+ if (res.error && res.error->reason == Response::Error::Reason::NotFound) {
+ // When the optional request could not be satisfied, don't treat it as an error.
+ // Instead, we make sure that the next request knows that there has been an optional
+ // request before by setting one of the prior* fields.
+ resource.priorExpires = Timestamp{ Seconds::zero() };
+ } else {
+ loadedData(res);
+ }
+
+ if (necessity == Necessity::Required) {
+ loadRequired();
+ }
+ });
+}
+
+template <typename T>
+void TileLoader<T>::makeRequired() {
+ if (!request) {
+ loadRequired();
+ }
+}
+
+template <typename T>
+void TileLoader<T>::makeOptional() {
+ if (resource.necessity == Resource::Required && request) {
+ // Abort a potential HTTP request.
+ request.reset();
+ }
+}
+
+template <typename T>
+void TileLoader<T>::loadedData(const Response& res) {
+ if (res.error && res.error->reason != Response::Error::Reason::NotFound) {
+ tile.setError(std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
+ resource.priorExpires = res.expires;
+ // Do not notify the tile; when we get this message, it already has the current
+ // version of the data.
+ } else {
+ resource.priorModified = res.modified;
+ resource.priorExpires = res.expires;
+ resource.priorEtag = res.etag;
+ tile.setData(res.noContent ? nullptr : res.data, res.modified, res.expires);
+ }
+}
+
+template <typename T>
+void TileLoader<T>::loadRequired() {
+ assert(!request);
+
+ resource.necessity = Resource::Required;
+ request = fileSource.request(resource, [this](Response res) { loadedData(res); });
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/tile/tile_observer.hpp b/src/mbgl/tile/tile_observer.hpp
new file mode 100644
index 0000000000..96ded11fbb
--- /dev/null
+++ b/src/mbgl/tile/tile_observer.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <exception>
+
+namespace mbgl {
+
+class Tile;
+
+class TileObserver {
+public:
+ virtual ~TileObserver() = default;
+
+ virtual void onTileLoaded(Tile&, bool /*isNewTile*/) {}
+ virtual void onTileError(Tile&, std::exception_ptr) {}
+ virtual void onNeedsRepaint() {}
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/tile/tile_worker.cpp b/src/mbgl/tile/tile_worker.cpp
index 1890aa7c47..5761ca83b9 100644
--- a/src/mbgl/tile/tile_worker.cpp
+++ b/src/mbgl/tile/tile_worker.cpp
@@ -1,9 +1,7 @@
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/tile/tile_worker.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/style/bucket_parameters.hpp>
-#include <mbgl/style/layers/background_layer.hpp>
-#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
@@ -13,21 +11,20 @@
#include <mbgl/util/constants.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/exception.hpp>
+
#include <utility>
namespace mbgl {
-using namespace mbgl::style;
+using namespace style;
-TileWorker::TileWorker(const OverscaledTileID& id_,
- std::string sourceID_,
+TileWorker::TileWorker(OverscaledTileID id_,
SpriteStore& spriteStore_,
GlyphAtlas& glyphAtlas_,
GlyphStore& glyphStore_,
- const util::Atomic<bool>& obsolete_,
+ const std::atomic<bool>& obsolete_,
const MapMode mode_)
- : id(id_),
- sourceID(std::move(sourceID_)),
+ : id(std::move(id_)),
spriteStore(spriteStore_),
glyphAtlas(glyphAtlas_),
glyphStore(glyphStore_),
@@ -40,14 +37,14 @@ TileWorker::~TileWorker() {
}
TileParseResult TileWorker::parseAllLayers(std::vector<std::unique_ptr<Layer>> layers_,
- std::unique_ptr<const GeometryTile> geometryTile_,
+ std::unique_ptr<const GeometryTileData> tileData_,
PlacementConfig config) {
// We're doing a fresh parse of the tile, because the underlying data has changed.
pending.clear();
placementPending.clear();
partialParse = false;
featureIndex = std::make_unique<FeatureIndex>();
- geometryTile = std::move(geometryTile_);
+ tileData = std::move(tileData_);
// Store the layers for use in redoPlacement.
layers = std::move(layers_);
@@ -98,7 +95,7 @@ TileParseResult TileWorker::prepareResult(const PlacementConfig& config) {
if (result.complete) {
featureIndex->setCollisionTile(placeLayers(config));
result.featureIndex = std::move(featureIndex);
- result.geometryTile = std::move(geometryTile);
+ result.tileData = std::move(tileData);
}
return std::move(result);
@@ -135,19 +132,7 @@ void TileWorker::parseLayer(const Layer* layer) {
if (obsolete)
return;
- // Background and custom layers are special cases.
- if (layer->is<BackgroundLayer>() || layer->is<CustomLayer>())
- return;
-
- // Skip this bucket if we are to not render this
- if ((layer->baseImpl->source != sourceID) ||
- (id.overscaledZ < std::floor(layer->baseImpl->minZoom)) ||
- (id.overscaledZ >= std::ceil(layer->baseImpl->maxZoom)) ||
- (layer->baseImpl->visibility == VisibilityType::None)) {
- return;
- }
-
- auto geometryLayer = geometryTile->getLayer(layer->baseImpl->sourceLayer);
+ auto geometryLayer = tileData->getLayer(layer->baseImpl->sourceLayer);
if (!geometryLayer) {
// The layer specified in the bucket does not exist. Do nothing.
if (debug::tileParseWarnings) {
@@ -188,4 +173,4 @@ void TileWorker::insertBucket(const std::string& name, std::unique_ptr<Bucket> b
}
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/tile/tile_worker.hpp b/src/mbgl/tile/tile_worker.hpp
index 631a8c929f..872c058b43 100644
--- a/src/mbgl/tile/tile_worker.hpp
+++ b/src/mbgl/tile/tile_worker.hpp
@@ -2,13 +2,13 @@
#include <mbgl/map/mode.hpp>
#include <mbgl/tile/tile_id.hpp>
-#include <mbgl/util/atomic.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/variant.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/text/placement_config.hpp>
#include <mbgl/geometry/feature_index.hpp>
+#include <atomic>
#include <string>
#include <memory>
#include <mutex>
@@ -18,7 +18,7 @@
namespace mbgl {
class CollisionTile;
-class GeometryTile;
+class GeometryTileData;
class SpriteStore;
class GlyphAtlas;
class GlyphStore;
@@ -27,7 +27,7 @@ class Bucket;
namespace style {
class Layer;
class SymbolLayer;
-}
+} // namespace style
// We're using this class to shuttle the resulting buckets from the worker thread to the MapContext
// thread. This class is movable-only because the vector contains movable-only value elements.
@@ -36,7 +36,7 @@ public:
bool complete = false;
std::unordered_map<std::string, std::unique_ptr<Bucket>> buckets;
std::unique_ptr<FeatureIndex> featureIndex;
- std::unique_ptr<const GeometryTile> geometryTile;
+ std::unique_ptr<const GeometryTileData> tileData;
};
using TileParseResult = variant<
@@ -45,17 +45,16 @@ using TileParseResult = variant<
class TileWorker : public util::noncopyable {
public:
- TileWorker(const OverscaledTileID&,
- std::string sourceID,
+ TileWorker(OverscaledTileID,
SpriteStore&,
GlyphAtlas&,
GlyphStore&,
- const util::Atomic<bool>&,
+ const std::atomic<bool>&,
const MapMode);
~TileWorker();
TileParseResult parseAllLayers(std::vector<std::unique_ptr<style::Layer>>,
- std::unique_ptr<const GeometryTile> geometryTile,
+ std::unique_ptr<const GeometryTileData> tileData,
PlacementConfig);
TileParseResult parsePendingLayers(PlacementConfig);
@@ -70,12 +69,11 @@ private:
std::unique_ptr<CollisionTile> placeLayers(PlacementConfig);
const OverscaledTileID id;
- const std::string sourceID;
SpriteStore& spriteStore;
GlyphAtlas& glyphAtlas;
GlyphStore& glyphStore;
- const util::Atomic<bool>& obsolete;
+ const std::atomic<bool>& obsolete;
const MapMode mode;
bool partialParse = false;
@@ -83,7 +81,7 @@ private:
std::vector<std::unique_ptr<style::Layer>> layers;
std::unique_ptr<FeatureIndex> featureIndex;
- std::unique_ptr<const GeometryTile> geometryTile;
+ std::unique_ptr<const GeometryTileData> tileData;
// Contains buckets that we couldn't parse so far due to missing resources.
// They will be attempted on subsequent parses.
diff --git a/src/mbgl/tile/vector_tile.cpp b/src/mbgl/tile/vector_tile.cpp
index 5126d0ce83..6a3c51c05d 100644
--- a/src/mbgl/tile/vector_tile.cpp
+++ b/src/mbgl/tile/vector_tile.cpp
@@ -1,14 +1,94 @@
#include <mbgl/tile/vector_tile.hpp>
-#include <mbgl/style/source.hpp>
-#include <mbgl/storage/resource.hpp>
-#include <mbgl/storage/response.hpp>
-#include <mbgl/storage/file_source.hpp>
-#include <mbgl/util/url.hpp>
+#include <mbgl/tile/tile_loader_impl.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
+#include <mbgl/style/update_parameters.hpp>
+#include <protozero/pbf_reader.hpp>
+
+#include <map>
+#include <unordered_map>
+#include <functional>
#include <utility>
namespace mbgl {
+class VectorTileLayer;
+
+using pbf_iter_type = protozero::pbf_reader::const_uint32_iterator;
+using packed_iter_type = std::pair<pbf_iter_type,pbf_iter_type>;
+
+class VectorTileFeature : public GeometryTileFeature {
+public:
+ VectorTileFeature(protozero::pbf_reader, const VectorTileLayer&);
+
+ FeatureType getType() const override { return type; }
+ optional<Value> getValue(const std::string&) const override;
+ std::unordered_map<std::string,Value> getProperties() const override;
+ optional<FeatureIdentifier> getID() const override;
+ GeometryCollection getGeometries() const override;
+
+private:
+ const VectorTileLayer& layer;
+ optional<FeatureIdentifier> id;
+ FeatureType type = FeatureType::Unknown;
+ packed_iter_type tags_iter;
+ packed_iter_type geometry_iter;
+};
+
+class VectorTileLayer : public GeometryTileLayer {
+public:
+ VectorTileLayer(protozero::pbf_reader);
+
+ std::size_t featureCount() const override { return features.size(); }
+ util::ptr<const GeometryTileFeature> getFeature(std::size_t) const override;
+ std::string getName() const override;
+
+private:
+ friend class VectorTileData;
+ friend class VectorTileFeature;
+
+ std::string name;
+ uint32_t version = 1;
+ uint32_t extent = 4096;
+ std::map<std::string, uint32_t> keysMap;
+ std::vector<std::reference_wrapper<const std::string>> keys;
+ std::vector<Value> values;
+ std::vector<protozero::pbf_reader> features;
+};
+
+class VectorTileData : public GeometryTileData {
+public:
+ VectorTileData(std::shared_ptr<const std::string> data);
+
+ util::ptr<GeometryTileLayer> getLayer(const std::string&) const override;
+
+private:
+ std::shared_ptr<const std::string> data;
+ mutable bool parsed = false;
+ mutable std::map<std::string, util::ptr<GeometryTileLayer>> layers;
+};
+
+VectorTile::VectorTile(const OverscaledTileID& id_,
+ std::string sourceID_,
+ const style::UpdateParameters& parameters,
+ const Tileset& tileset)
+ : GeometryTile(id_, sourceID_, parameters.style, parameters.mode),
+ loader(*this, id_, parameters, tileset) {
+}
+
+void VectorTile::setNecessity(Necessity necessity) {
+ loader.setNecessity(necessity);
+}
+
+void VectorTile::setData(std::shared_ptr<const std::string> data_,
+ optional<Timestamp> modified_,
+ optional<Timestamp> expires_) {
+ modified = modified_;
+ expires = expires_;
+
+ GeometryTile::setData(data_ ? std::make_unique<VectorTileData>(data_) : nullptr);
+}
+
Value parseValue(protozero::pbf_reader data) {
while (data.next())
{
@@ -40,7 +120,7 @@ VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf, const Ve
while (feature_pbf.next()) {
switch (feature_pbf.tag()) {
case 1: // id
- id = feature_pbf.get_uint64();
+ id = { feature_pbf.get_uint64() };
break;
case 2: // tags
tags_iter = feature_pbf.get_packed_uint32();
@@ -105,7 +185,7 @@ std::unordered_map<std::string,Value> VectorTileFeature::getProperties() const {
return properties;
}
-optional<uint64_t> VectorTileFeature::getID() const {
+optional<FeatureIdentifier> VectorTileFeature::getID() const {
return id;
}
@@ -159,11 +239,11 @@ GeometryCollection VectorTileFeature::getGeometries() const {
return fixupPolygons(lines);
}
-VectorTile::VectorTile(std::shared_ptr<const std::string> data_)
+VectorTileData::VectorTileData(std::shared_ptr<const std::string> data_)
: data(std::move(data_)) {
}
-util::ptr<GeometryTileLayer> VectorTile::getLayer(const std::string& name) const {
+util::ptr<GeometryTileLayer> VectorTileData::getLayer(const std::string& name) const {
if (!parsed) {
parsed = true;
protozero::pbf_reader tile_pbf(*data);
@@ -220,28 +300,4 @@ std::string VectorTileLayer::getName() const {
return name;
}
-VectorTileMonitor::VectorTileMonitor(const OverscaledTileID& tileID_, float pixelRatio_,
- const std::string& urlTemplate_, FileSource& fileSource_)
- : tileID(tileID_),
- pixelRatio(pixelRatio_),
- urlTemplate(urlTemplate_),
- fileSource(fileSource_) {
-}
-
-std::unique_ptr<AsyncRequest> VectorTileMonitor::monitorTile(const GeometryTileMonitor::Callback& callback) {
- const Resource resource = Resource::tile(urlTemplate, pixelRatio, tileID.canonical.x,
- tileID.canonical.y, tileID.canonical.z);
- return fileSource.request(resource, [callback, this](Response res) {
- if (res.error) {
- callback(std::make_exception_ptr(std::runtime_error(res.error->message)), nullptr, res.modified, res.expires);
- } else if (res.notModified) {
- return;
- } else if (res.noContent) {
- callback(nullptr, nullptr, res.modified, res.expires);
- } else {
- callback(nullptr, std::make_unique<VectorTile>(res.data), res.modified, res.expires);
- }
- });
-}
-
} // namespace mbgl
diff --git a/src/mbgl/tile/vector_tile.hpp b/src/mbgl/tile/vector_tile.hpp
index 9e81f0ec8c..2568a277e6 100644
--- a/src/mbgl/tile/vector_tile.hpp
+++ b/src/mbgl/tile/vector_tile.hpp
@@ -1,85 +1,30 @@
#pragma once
#include <mbgl/tile/geometry_tile.hpp>
-#include <mbgl/tile/tile_id.hpp>
-#include <protozero/pbf_reader.hpp>
-
-#include <map>
-#include <unordered_map>
-#include <functional>
+#include <mbgl/tile/tile_loader.hpp>
namespace mbgl {
-class VectorTileLayer;
-
-using pbf_iter_type = protozero::pbf_reader::const_uint32_iterator;
-using packed_iter_type = std::pair<pbf_iter_type,pbf_iter_type>;
-
-class VectorTileFeature : public GeometryTileFeature {
-public:
- VectorTileFeature(protozero::pbf_reader, const VectorTileLayer&);
+class Tileset;
- FeatureType getType() const override { return type; }
- optional<Value> getValue(const std::string&) const override;
- std::unordered_map<std::string,Value> getProperties() const override;
- optional<uint64_t> getID() const override;
- GeometryCollection getGeometries() const override;
-
-private:
- const VectorTileLayer& layer;
- optional<uint64_t> id;
- FeatureType type = FeatureType::Unknown;
- packed_iter_type tags_iter;
- packed_iter_type geometry_iter;
-};
-
-class VectorTileLayer : public GeometryTileLayer {
-public:
- VectorTileLayer(protozero::pbf_reader);
-
- std::size_t featureCount() const override { return features.size(); }
- util::ptr<const GeometryTileFeature> getFeature(std::size_t) const override;
- std::string getName() const override;
-
-private:
- friend class VectorTile;
- friend class VectorTileFeature;
-
- std::string name;
- uint32_t version = 1;
- uint32_t extent = 4096;
- std::map<std::string, uint32_t> keysMap;
- std::vector<std::reference_wrapper<const std::string>> keys;
- std::vector<Value> values;
- std::vector<protozero::pbf_reader> features;
-};
+namespace style {
+class UpdateParameters;
+} // namespace style
class VectorTile : public GeometryTile {
public:
- VectorTile(std::shared_ptr<const std::string> data);
-
- util::ptr<GeometryTileLayer> getLayer(const std::string&) const override;
-
-private:
- std::shared_ptr<const std::string> data;
- mutable bool parsed = false;
- mutable std::map<std::string, util::ptr<GeometryTileLayer>> layers;
-};
-
-class TileID;
-class FileSource;
-
-class VectorTileMonitor : public GeometryTileMonitor {
-public:
- VectorTileMonitor(const OverscaledTileID&, float pixelRatio, const std::string& urlTemplate, FileSource&);
+ VectorTile(const OverscaledTileID&,
+ std::string sourceID,
+ const style::UpdateParameters&,
+ const Tileset&);
- std::unique_ptr<AsyncRequest> monitorTile(const GeometryTileMonitor::Callback&) override;
+ void setNecessity(Necessity) final;
+ void setData(std::shared_ptr<const std::string> data,
+ optional<Timestamp> modified,
+ optional<Timestamp> expires);
private:
- OverscaledTileID tileID;
- float pixelRatio;
- std::string urlTemplate;
- FileSource& fileSource;
+ TileLoader<VectorTile> loader;
};
} // namespace mbgl
diff --git a/src/mbgl/tile/vector_tile_data.cpp b/src/mbgl/tile/vector_tile_data.cpp
deleted file mode 100644
index 1ab2566a25..0000000000
--- a/src/mbgl/tile/vector_tile_data.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-#include <mbgl/tile/vector_tile_data.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
-#include <mbgl/style/layer_impl.hpp>
-#include <mbgl/util/worker.hpp>
-#include <mbgl/util/work_request.hpp>
-#include <mbgl/style/style.hpp>
-#include <mbgl/storage/file_source.hpp>
-#include <mbgl/geometry/feature_index.hpp>
-#include <mbgl/text/collision_tile.hpp>
-#include <mbgl/map/transform_state.hpp>
-
-namespace mbgl {
-
-VectorTileData::VectorTileData(const OverscaledTileID& id_,
- std::unique_ptr<GeometryTileMonitor> monitor_,
- std::string sourceID,
- style::Style& style_,
- const MapMode mode_,
- const std::function<void(std::exception_ptr)>& callback)
- : TileData(id_),
- style(style_),
- worker(style_.workers),
- tileWorker(id_,
- sourceID,
- *style_.spriteStore,
- *style_.glyphAtlas,
- *style_.glyphStore,
- obsolete,
- mode_),
- monitor(std::move(monitor_))
-{
- tileRequest = monitor->monitorTile([callback, this](std::exception_ptr err,
- std::unique_ptr<GeometryTile> tile,
- optional<Timestamp> modified_,
- optional<Timestamp> expires_) {
- if (err) {
- callback(err);
- return;
- }
-
- modified = modified_;
- expires = expires_;
-
- if (!tile) {
- // This is a 404 response. We're treating these as empty tiles.
- workRequest.reset();
- availableData = DataAvailability::All;
- buckets.clear();
- callback(err);
- return;
- }
-
- // Mark the tile as pending again if it was complete before to prevent signaling a complete
- // state despite pending parse operations.
- if (availableData == DataAvailability::All) {
- availableData = DataAvailability::Some;
- }
-
- // Kick off a fresh parse of this tile. This happens when the tile is new, or
- // when tile data changed. Replacing the workdRequest will cancel a pending work
- // request in case there is one.
- workRequest.reset();
- workRequest = worker.parseGeometryTile(tileWorker, style.getLayers(), std::move(tile), targetConfig, [callback, this, config = targetConfig] (TileParseResult result) {
- workRequest.reset();
-
- std::exception_ptr error;
- if (result.is<TileParseResultData>()) {
- auto& resultBuckets = result.get<TileParseResultData>();
- availableData =
- resultBuckets.complete ? DataAvailability::All : DataAvailability::Some;
-
- // Persist the configuration we just placed so that we can later check whether we need to
- // place again in case the configuration has changed.
- placedConfig = config;
-
- // Move over all buckets we received in this parse request, potentially overwriting
- // existing buckets in case we got a refresh parse.
- buckets = std::move(resultBuckets.buckets);
-
- if (isComplete()) {
- featureIndex = std::move(resultBuckets.featureIndex);
- geometryTile = std::move(resultBuckets.geometryTile);
- }
-
- } else {
- // This is triggered when parsing fails (e.g. due to an invalid vector tile)
- error = result.get<std::exception_ptr>();
- availableData = DataAvailability::All;
- }
-
- callback(error);
- });
- });
-}
-
-VectorTileData::~VectorTileData() {
- cancel();
-}
-
-bool VectorTileData::parsePending(std::function<void(std::exception_ptr)> callback) {
- if (workRequest) {
- // There's already parsing or placement going on.
- return false;
- }
-
- workRequest.reset();
- workRequest = worker.parsePendingGeometryTileLayers(tileWorker, targetConfig, [this, callback, config = targetConfig] (TileParseResult result) {
- workRequest.reset();
-
- std::exception_ptr error;
- if (result.is<TileParseResultData>()) {
- auto& resultBuckets = result.get<TileParseResultData>();
- availableData =
- resultBuckets.complete ? DataAvailability::All : DataAvailability::Some;
-
- // Move over all buckets we received in this parse request, potentially overwriting
- // existing buckets in case we got a refresh parse.
- for (auto& bucket : resultBuckets.buckets) {
- buckets[bucket.first] = std::move(bucket.second);
- }
-
- // Persist the configuration we just placed so that we can later check whether we need to
- // place again in case the configuration has changed.
- placedConfig = config;
-
- if (isComplete()) {
- featureIndex = std::move(resultBuckets.featureIndex);
- geometryTile = std::move(resultBuckets.geometryTile);
- }
-
- } else {
- error = result.get<std::exception_ptr>();
- availableData = DataAvailability::All;
- }
-
- callback(error);
- });
-
- return true;
-}
-
-Bucket* VectorTileData::getBucket(const style::Layer& layer) {
- const auto it = buckets.find(layer.baseImpl->bucketName());
- if (it == buckets.end()) {
- return nullptr;
- }
-
- assert(it->second);
- return it->second.get();
-}
-
-void VectorTileData::redoPlacement(const PlacementConfig newConfig, const std::function<void()>& callback) {
- if (newConfig != placedConfig) {
- targetConfig = newConfig;
-
- redoPlacement(callback);
- }
-}
-
-void VectorTileData::redoPlacement(const std::function<void()>& callback) {
- // Don't start a new placement request when the current one hasn't completed yet, or when
- // we are parsing buckets.
- if (workRequest) return;
-
- workRequest = worker.redoPlacement(tileWorker, buckets, targetConfig, [this, callback, config = targetConfig](std::unique_ptr<CollisionTile> collisionTile) {
- workRequest.reset();
-
- // Persist the configuration we just placed so that we can later check whether we need to
- // place again in case the configuration has changed.
- placedConfig = config;
-
- for (auto& bucket : buckets) {
- bucket.second->swapRenderData();
- }
-
- if (featureIndex) {
- featureIndex->setCollisionTile(std::move(collisionTile));
- }
-
- // The target configuration could have changed since we started placement. In this case,
- // we're starting another placement run.
- if (placedConfig != targetConfig) {
- redoPlacement(callback);
- } else {
- callback();
- }
- });
-}
-
-void VectorTileData::queryRenderedFeatures(
- std::unordered_map<std::string, std::vector<Feature>>& result,
- const GeometryCoordinates& queryGeometry,
- const TransformState& transformState,
- const optional<std::vector<std::string>>& layerIDs) {
-
- if (!featureIndex || !geometryTile) return;
-
- featureIndex->query(result,
- { queryGeometry },
- transformState.getAngle(),
- util::tileSize * id.overscaleFactor(),
- std::pow(2, transformState.getZoom() - id.overscaledZ),
- layerIDs,
- *geometryTile,
- id.canonical,
- style);
-}
-
-void VectorTileData::cancel() {
- obsolete = true;
- tileRequest.reset();
- workRequest.reset();
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/tile/vector_tile_data.hpp b/src/mbgl/tile/vector_tile_data.hpp
deleted file mode 100644
index df2a23fda6..0000000000
--- a/src/mbgl/tile/vector_tile_data.hpp
+++ /dev/null
@@ -1,75 +0,0 @@
-#pragma once
-
-#include <mbgl/tile/tile_data.hpp>
-#include <mbgl/tile/tile_worker.hpp>
-#include <mbgl/text/placement_config.hpp>
-#include <mbgl/util/atomic.hpp>
-#include <mbgl/util/feature.hpp>
-
-#include <memory>
-#include <unordered_map>
-
-namespace mbgl {
-
-class AsyncRequest;
-class GeometryTileMonitor;
-class FeatureIndex;
-
-namespace style {
-class Style;
-}
-
-class VectorTileData : public TileData {
-public:
- VectorTileData(const OverscaledTileID&,
- std::unique_ptr<GeometryTileMonitor> monitor,
- std::string sourceID,
- style::Style&,
- const MapMode,
- const std::function<void(std::exception_ptr)>& callback);
-
- ~VectorTileData();
-
- Bucket* getBucket(const style::Layer&) override;
-
- bool parsePending(std::function<void(std::exception_ptr)> callback) override;
-
- void redoPlacement(PlacementConfig config, const std::function<void()>&) override;
- void redoPlacement(const std::function<void()>&) override;
-
- void queryRenderedFeatures(
- std::unordered_map<std::string, std::vector<Feature>>& result,
- const GeometryCoordinates& queryGeometry,
- const TransformState&,
- const optional<std::vector<std::string>>& layerIDs) override;
-
- void cancel() override;
-
-private:
- style::Style& style;
- Worker& worker;
- TileWorker tileWorker;
-
- std::unique_ptr<GeometryTileMonitor> monitor;
- std::unique_ptr<AsyncRequest> tileRequest;
- std::unique_ptr<AsyncRequest> workRequest;
-
- // Contains all the Bucket objects for the tile. Buckets are render
- // objects and they get added by tile parsing operations.
- std::unordered_map<std::string, std::unique_ptr<Bucket>> buckets;
-
- std::unique_ptr<FeatureIndex> featureIndex;
- std::unique_ptr<const GeometryTile> geometryTile;
-
- // Stores the placement configuration of the text that is currently placed on the screen.
- PlacementConfig placedConfig;
-
- // Stores the placement configuration of how the text should be placed. This isn't necessarily
- // the one that is being displayed.
- PlacementConfig targetConfig;
-
- // Used to signal the worker that it should abandon parsing this tile as soon as possible.
- util::Atomic<bool> obsolete { false };
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/util/atomic.hpp b/src/mbgl/util/atomic.hpp
deleted file mode 100644
index 3f68bf46a5..0000000000
--- a/src/mbgl/util/atomic.hpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#pragma once
-
-#include <atomic>
-#include <mutex>
-
-namespace mbgl {
-namespace util {
-
-// std::atomic<bool> is implemented lock free which
-// is not supported by ARMv5 but the code generated
-// seems to be using that and not working at all,
-// thus, this naive implementation using mutexes.
-#if defined(__ANDROID__) && defined(__ARM_ARCH_5TE__)
-
-template <typename T>
-class Atomic {
-public:
- Atomic() = default;
- explicit Atomic(const T& data_) : data(data_) {}
-
- void operator=(const T& other) {
- std::lock_guard<std::mutex> lock(mtx);
- data = other;
- }
-
- operator bool() const {
- std::lock_guard<std::mutex> lock(mtx);
-
- return data;
- }
-
-private:
- T data;
- mutable std::mutex mtx;
-};
-
-#else
-
-template <typename T>
-using Atomic = std::atomic<T>;
-
-#endif
-
-} // namespace util
-} // namespace mbgl
diff --git a/src/mbgl/util/clip_id.hpp b/src/mbgl/util/clip_id.hpp
index 064a7acf94..de2dc51919 100644
--- a/src/mbgl/util/clip_id.hpp
+++ b/src/mbgl/util/clip_id.hpp
@@ -11,20 +11,18 @@
namespace mbgl {
-class Tile;
-
struct ClipID {
- inline ClipID() {}
- inline ClipID(const std::string &mask_, const std::string &reference_) : mask(mask_), reference(reference_) {}
+ ClipID() {}
+ ClipID(const std::string &mask_, const std::string &reference_) : mask(mask_), reference(reference_) {}
std::bitset<8> mask;
std::bitset<8> reference;
- inline bool operator==(const ClipID &other) const {
+ bool operator==(const ClipID &other) const {
return mask == other.mask && reference == other.reference;
}
- inline ClipID& operator|=(const ClipID &other) {
+ ClipID& operator|=(const ClipID &other) {
mask |= other.mask;
reference |= other.reference;
return *this;
diff --git a/src/mbgl/util/color.cpp b/src/mbgl/util/color.cpp
new file mode 100644
index 0000000000..eea897d3ab
--- /dev/null
+++ b/src/mbgl/util/color.cpp
@@ -0,0 +1,20 @@
+#include <mbgl/util/color.hpp>
+
+#include <csscolorparser/csscolorparser.hpp>
+
+namespace mbgl {
+
+optional<Color> Color::parse(const std::string& s) {
+ CSSColorParser::Color css_color = CSSColorParser::parse(s);
+
+ // Premultiply the color.
+ const float factor = css_color.a / 255;
+ return {{
+ css_color.r * factor,
+ css_color.g * factor,
+ css_color.b * factor,
+ css_color.a
+ }};
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/util/convert.cpp b/src/mbgl/util/convert.cpp
new file mode 100644
index 0000000000..97bfe9108d
--- /dev/null
+++ b/src/mbgl/util/convert.cpp
@@ -0,0 +1,9 @@
+#include <mbgl/util/convert.hpp>
+
+namespace mbgl {
+namespace util {
+
+template std::array<float, 2> convert(const std::array<int32_t, 2>&);
+
+} // namespace util
+} // namespace mbgl
diff --git a/src/mbgl/util/dtoa.cpp b/src/mbgl/util/dtoa.cpp
index 7ccee345f6..dd4fba0f89 100644
--- a/src/mbgl/util/dtoa.cpp
+++ b/src/mbgl/util/dtoa.cpp
@@ -9,7 +9,7 @@ namespace {
// From https://github.com/miloyip/rapidjson/blob/master/include/rapidjson/internal/dtoa.h
-inline char* Prettify(char* buffer, int length, int k) {
+char* Prettify(char* buffer, int length, int k) {
constexpr int maxDecimalPlaces = 324;
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
@@ -93,5 +93,13 @@ char* dtoa(double value, char* buffer) {
}
}
+std::string dtoa(double value) {
+ std::string data;
+ data.resize(25);
+ auto end = dtoa(value, const_cast<char*>(data.data()));
+ data.resize(end - data.data());
+ return data;
+}
+
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/dtoa.hpp b/src/mbgl/util/dtoa.hpp
index 17614732db..db7d309452 100644
--- a/src/mbgl/util/dtoa.hpp
+++ b/src/mbgl/util/dtoa.hpp
@@ -6,14 +6,7 @@ namespace mbgl {
namespace util {
char* dtoa(double value, char* buffer);
-
-inline std::string dtoa(double value) {
- std::string data;
- data.resize(25);
- auto end = dtoa(value, const_cast<char*>(data.data()));
- data.resize(end - data.data());
- return data;
-}
+std::string dtoa(double value);
} // end namespace util
} // end namespace mbgl
diff --git a/src/mbgl/util/exclusive.hpp b/src/mbgl/util/exclusive.hpp
index 946604af69..844588dc90 100644
--- a/src/mbgl/util/exclusive.hpp
+++ b/src/mbgl/util/exclusive.hpp
@@ -10,12 +10,12 @@ namespace util {
template <class T>
class exclusive {
public:
- inline exclusive(T* val, std::unique_ptr<std::lock_guard<std::mutex>> mtx) : ptr(val), lock(std::move(mtx)) {}
+ exclusive(T* val, std::unique_ptr<std::lock_guard<std::mutex>> mtx) : ptr(val), lock(std::move(mtx)) {}
- inline T* operator->() { return ptr; }
- inline const T* operator->() const { return ptr; }
- inline T* operator*() { return ptr; }
- inline const T* operator*() const { return ptr; }
+ T* operator->() { return ptr; }
+ const T* operator->() const { return ptr; }
+ T* operator*() { return ptr; }
+ const T* operator*() const { return ptr; }
private:
T *ptr;
diff --git a/src/mbgl/util/geo.cpp b/src/mbgl/util/geo.cpp
index dd40af882b..fe24334e82 100644
--- a/src/mbgl/util/geo.cpp
+++ b/src/mbgl/util/geo.cpp
@@ -8,12 +8,12 @@ namespace mbgl {
namespace {
-inline double lat(const uint8_t z, const int64_t y) {
+double lat(const uint8_t z, const int64_t y) {
const double n = M_PI - 2.0 * M_PI * y / std::pow(2.0, z);
return util::RAD2DEG * std::atan(0.5 * (std::exp(n) - std::exp(-n)));
}
-inline double lon(const uint8_t z, const int64_t x) {
+double lon(const uint8_t z, const int64_t x) {
return x / std::pow(2.0, z) * util::DEGREES_MAX - util::LONGITUDE_MAX;
}
diff --git a/src/mbgl/util/grid_index.cpp b/src/mbgl/util/grid_index.cpp
index 4877a90e72..b3afd3fdc8 100644
--- a/src/mbgl/util/grid_index.cpp
+++ b/src/mbgl/util/grid_index.cpp
@@ -1,5 +1,6 @@
#include <mbgl/util/grid_index.hpp>
#include <mbgl/geometry/feature_index.hpp>
+#include <mbgl/math/minmax.hpp>
#include <unordered_set>
@@ -17,7 +18,7 @@ GridIndex<T>::GridIndex(int32_t extent_, int32_t n_, int32_t padding_) :
max(extent + double(padding) / n * extent)
{
cells.resize(d * d);
- };
+ }
template <class T>
void GridIndex<T>::insert(T&& t, const BBox& bbox) {
@@ -28,9 +29,10 @@ void GridIndex<T>::insert(T&& t, const BBox& bbox) {
auto cx2 = convertToCellCoord(bbox.max.x);
auto cy2 = convertToCellCoord(bbox.max.y);
- for (int32_t x = cx1; x <= cx2; x++) {
- for (int32_t y = cy1; y <= cy2; y++) {
- auto cellIndex = d * y + x;
+ int32_t x, y, cellIndex;
+ for (x = cx1; x <= cx2; ++x) {
+ for (y = cy1; y <= cy2; ++y) {
+ cellIndex = d * y + x;
cells[cellIndex].push_back(uid);
}
}
@@ -48,9 +50,10 @@ std::vector<T> GridIndex<T>::query(const BBox& queryBBox) const {
auto cx2 = convertToCellCoord(queryBBox.max.x);
auto cy2 = convertToCellCoord(queryBBox.max.y);
- for (int32_t x = cx1; x <= cx2; x++) {
- for (int32_t y = cy1; y <= cy2; y++) {
- auto cellIndex = d * y + x;
+ int32_t x, y, cellIndex;
+ for (x = cx1; x <= cx2; ++x) {
+ for (y = cy1; y <= cy2; ++y) {
+ cellIndex = d * y + x;
for (auto uid : cells[cellIndex]) {
if (seenUids.count(uid) == 0) {
seenUids.insert(uid);
@@ -75,8 +78,8 @@ std::vector<T> GridIndex<T>::query(const BBox& queryBBox) const {
template <class T>
int32_t GridIndex<T>::convertToCellCoord(int32_t x) const {
- return std::max(0.0, std::min(d - 1.0, std::floor(x * scale) + padding));
+ return util::max(0.0, util::min(d - 1.0, std::floor(x * scale) + padding));
}
template class GridIndex<IndexedSubfeature>;
-}
+} // namespace mbgl
diff --git a/src/mbgl/util/grid_index.hpp b/src/mbgl/util/grid_index.hpp
index 656a4bdbd8..8ef8fb35b7 100644
--- a/src/mbgl/util/grid_index.hpp
+++ b/src/mbgl/util/grid_index.hpp
@@ -35,4 +35,4 @@ private:
};
-}
+} // namespace mbgl
diff --git a/src/mbgl/util/interpolate.hpp b/src/mbgl/util/interpolate.hpp
index 18a9e6bbc5..8b9929fa4a 100644
--- a/src/mbgl/util/interpolate.hpp
+++ b/src/mbgl/util/interpolate.hpp
@@ -5,6 +5,7 @@
#include <string>
#include <type_traits>
#include <utility>
+#include <mbgl/util/color.hpp>
namespace mbgl {
namespace util {
@@ -41,6 +42,19 @@ public:
}
};
+template <>
+struct Interpolator<Color> {
+public:
+ Color operator()(const Color& a, const Color& b, const double t) {
+ return {
+ interpolate(a.r, b.r, t),
+ interpolate(a.g, b.g, t),
+ interpolate(a.b, b.b, t),
+ interpolate(a.a, b.a, t)
+ };
+ }
+};
+
struct Uninterpolated {
template <class T>
T operator()(const T&, const T& b, const double) const {
diff --git a/src/mbgl/util/intersection_tests.cpp b/src/mbgl/util/intersection_tests.cpp
index 3e4ae27cd8..74b3bec388 100644
--- a/src/mbgl/util/intersection_tests.cpp
+++ b/src/mbgl/util/intersection_tests.cpp
@@ -143,5 +143,5 @@ bool multiPolygonIntersectsMultiPolygon(const GeometryCollection& multiPolygonA,
return false;
}
-}
-}
+} // namespace util
+} // namespace mbgl
diff --git a/src/mbgl/util/intersection_tests.hpp b/src/mbgl/util/intersection_tests.hpp
index a3ffe65cbf..be89d14ed6 100644
--- a/src/mbgl/util/intersection_tests.hpp
+++ b/src/mbgl/util/intersection_tests.hpp
@@ -1,6 +1,6 @@
#pragma once
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
namespace mbgl {
namespace util {
@@ -9,5 +9,5 @@ bool multiPolygonIntersectsBufferedMultiPoint(const GeometryCollection&, const G
bool multiPolygonIntersectsBufferedMultiLine(const GeometryCollection&, const GeometryCollection&, float radius);
bool multiPolygonIntersectsMultiPolygon(const GeometryCollection&, const GeometryCollection&);
-}
+} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/io.hpp b/src/mbgl/util/io.hpp
index 2679eb5360..795a465328 100644
--- a/src/mbgl/util/io.hpp
+++ b/src/mbgl/util/io.hpp
@@ -7,7 +7,7 @@ namespace mbgl {
namespace util {
struct IOException : std::runtime_error {
- inline IOException(int err, const char* msg) : std::runtime_error(msg), code(err) {
+ IOException(int err, const char* msg) : std::runtime_error(msg), code(err) {
}
const int code = 0;
};
diff --git a/src/mbgl/util/mat2.cpp b/src/mbgl/util/mat2.cpp
index 6910244541..4fb5abafb8 100644
--- a/src/mbgl/util/mat2.cpp
+++ b/src/mbgl/util/mat2.cpp
@@ -24,7 +24,7 @@
#include <cmath>
-using namespace mbgl;
+namespace mbgl {
void matrix::identity(mat2& out) {
out[0] = 1.0f;
@@ -41,7 +41,7 @@ void matrix::rotate(mat2& out, const mat2& a, double rad) {
out[1] = a1 * c + a3 * s;
out[2] = a0 * -s + a2 * c;
out[3] = a1 * -s + a3 * c;
-};
+}
void matrix::scale(mat2& out, const mat2& a, double v0, double v1) {
double a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
@@ -50,3 +50,5 @@ void matrix::scale(mat2& out, const mat2& a, double v0, double v1) {
out[2] = a2 * v1;
out[3] = a3 * v1;
}
+
+} // namespace mbgl
diff --git a/src/mbgl/util/mat3.cpp b/src/mbgl/util/mat3.cpp
index f4ae8841d5..e2200867ce 100644
--- a/src/mbgl/util/mat3.cpp
+++ b/src/mbgl/util/mat3.cpp
@@ -24,7 +24,7 @@
#include <cmath>
-using namespace mbgl;
+namespace mbgl {
void matrix::identity(mat3& out) {
out[0] = 1.0f;
@@ -80,7 +80,7 @@ void matrix::rotate(mat3& out, const mat3& a, double rad) {
out[6] = a20;
out[7] = a21;
out[8] = a22;
-};
+}
void matrix::scale(mat3& out, const mat3& a, double x, double y) {
out[0] = x * a[0];
@@ -93,3 +93,5 @@ void matrix::scale(mat3& out, const mat3& a, double x, double y) {
out[7] = a[7];
out[8] = a[8];
}
+
+} // namespace mbgl
diff --git a/src/mbgl/util/math.cpp b/src/mbgl/util/math.cpp
index 0e86849ad3..7b1516c041 100644
--- a/src/mbgl/util/math.cpp
+++ b/src/mbgl/util/math.cpp
@@ -11,8 +11,8 @@ uint32_t ceil_log2(uint64_t x) {
uint32_t y = (((x & (x - 1)) == 0) ? 0 : 1);
uint32_t j = 32;
- for (int32_t i = 0; i < 6; i++) {
- const uint32_t k = (((x & t[i]) == 0) ? 0 : j);
+ for (const auto& i : t) {
+ const uint32_t k = (((x & i) == 0) ? 0 : j);
y += k;
x >>= k;
j >>= 1;
@@ -24,7 +24,7 @@ uint32_t ceil_log2(uint64_t x) {
double log2(double x) {
// log2() is producing wrong results on ARMv5 binaries
// running on ARMv7+ CPUs.
-#if defined(__ANDROID__) && defined(__ARM_ARCH_5TE__)
+#if defined(__ANDROID__)
return std::log(x) / 0.6931471805599453; // log(x) / log(2)
#else
return ::log2(x);
diff --git a/src/mbgl/util/math.hpp b/src/mbgl/util/math.hpp
index bfedc2a421..5d4220d0a2 100644
--- a/src/mbgl/util/math.hpp
+++ b/src/mbgl/util/math.hpp
@@ -14,18 +14,18 @@ namespace util {
// Find the angle of the two vectors, solving the formula for the cross product
// a x b = |a||b|sin(θ) for θ.
template <typename T = double, typename S>
-inline T angle_between(const Point<S>& a, const Point<S>& b) {
+T angle_between(const Point<S>& a, const Point<S>& b) {
return std::atan2((a.x * b.y - a.y * b.x), a.x * b.x + a.y * b.y);
}
template <typename T = double, typename S>
-inline T angle_to(const Point<S>& a, const Point<S>& b) {
+T angle_to(const Point<S>& a, const Point<S>& b) {
return std::atan2(a.y - b.y, a.x - b.x);
}
// Reflect an angle around 0 degrees
template <typename T>
-inline std::array<T, 2> flip(const std::array<T, 2>& c) {
+std::array<T, 2> flip(const std::array<T, 2>& c) {
return {{
static_cast<T>(2 * M_PI - c[0]),
static_cast<T>(2 * M_PI - c[1])
@@ -33,7 +33,7 @@ inline std::array<T, 2> flip(const std::array<T, 2>& c) {
}
template <typename T, typename S1, typename S2>
-inline Point<T> normal(const S1& a, const S2& b) {
+Point<T> normal(const S1& a, const S2& b) {
T dx = b.x - a.x;
T dy = b.y - a.y;
T c = std::sqrt(dx * dx + dy * dy);
@@ -41,12 +41,12 @@ inline Point<T> normal(const S1& a, const S2& b) {
}
template <typename T>
-inline T perp(const T& a) {
+T perp(const T& a) {
return T(-a.y, a.x);
}
template <typename T, typename S1, typename S2>
-inline T dist(const S1& a, const S2& b) {
+T dist(const S1& a, const S2& b) {
T dx = b.x - a.x;
T dy = b.y - a.y;
T c = std::sqrt(dx * dx + dy * dy);
@@ -54,7 +54,7 @@ inline T dist(const S1& a, const S2& b) {
}
template <typename T, typename S1, typename S2>
-inline T distSqr(const S1& a, const S2& b) {
+T distSqr(const S1& a, const S2& b) {
T dx = b.x - a.x;
T dy = b.y - a.y;
T c = dx * dx + dy * dy;
@@ -62,23 +62,23 @@ inline T distSqr(const S1& a, const S2& b) {
}
template <typename T>
-inline T round(const T& a) {
+T round(const T& a) {
return T(::round(a.x), ::round(a.y));
}
template <typename T>
-inline T length(T a, T b) {
+T length(T a, T b) {
return std::sqrt(a * a + b * b);
}
// Take the magnitude of vector a.
template <typename T = double, typename S>
-inline T mag(const S& a) {
+T mag(const S& a) {
return std::sqrt(a.x * a.x + a.y * a.y);
}
template <typename S>
-inline S unit(const S& a) {
+S unit(const S& a) {
auto magnitude = mag(a);
if (magnitude == 0) {
return a;
@@ -87,7 +87,7 @@ inline S unit(const S& a) {
}
template <typename T, typename S = double>
-inline T rotate(const T& a, S angle) {
+T rotate(const T& a, S angle) {
S cos = std::cos(angle);
S sin = std::sin(angle);
S x = cos * a.x - sin * a.y;
@@ -96,7 +96,7 @@ inline T rotate(const T& a, S angle) {
}
template <typename T>
-inline Point<T> matrixMultiply(const std::array<T, 4>& m, const Point<T>& p) {
+Point<T> matrixMultiply(const std::array<T, 4>& m, const Point<T>& p) {
return Point<T>(m[0] * p.x + m[1] * p.y, m[2] * p.x + m[3] * p.y);
}
diff --git a/src/mbgl/util/ptr.hpp b/src/mbgl/util/ptr.hpp
index 2dc8118181..87c4e9f7cf 100644
--- a/src/mbgl/util/ptr.hpp
+++ b/src/mbgl/util/ptr.hpp
@@ -10,14 +10,14 @@ template <typename T>
class ptr : public ::std::shared_ptr<T> {
public:
template <typename... Args>
- inline ptr(Args &&... args)
+ ptr(Args &&... args)
: ::std::shared_ptr<T>(::std::forward<Args>(args)...) {}
- inline auto operator->() const -> decltype(this->::std::shared_ptr<T>::operator->()) {
+ auto operator->() const -> decltype(this->::std::shared_ptr<T>::operator->()) {
assert(*this);
return ::std::shared_ptr<T>::operator->();
}
- inline auto operator*() const -> decltype(this->::std::shared_ptr<T>::operator*()) {
+ auto operator*() const -> decltype(this->::std::shared_ptr<T>::operator*()) {
assert(*this);
return ::std::shared_ptr<T>::operator*();
}
diff --git a/src/mbgl/util/raster.cpp b/src/mbgl/util/raster.cpp
index 3146a00513..3f9cb467b9 100644
--- a/src/mbgl/util/raster.cpp
+++ b/src/mbgl/util/raster.cpp
@@ -1,5 +1,6 @@
#include <mbgl/platform/platform.hpp>
#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/gl_config.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/util/raster.hpp>
@@ -7,59 +8,80 @@
#include <cassert>
#include <cstring>
-using namespace mbgl;
-
-Raster::Raster(gl::TexturePool& texturePool_)
- : texturePool(texturePool_)
-{}
+namespace mbgl {
bool Raster::isLoaded() const {
- std::lock_guard<std::mutex> lock(mtx);
return loaded;
}
-void Raster::load(PremultipliedImage image) {
+void Raster::load(PremultipliedImage image, uint32_t mipmapLevel) {
assert(image.data.get());
- img = std::move(image);
- width = GLsizei(img.width);
- height = GLsizei(img.height);
+ if (images.size() <= mipmapLevel) {
+ images.resize(mipmapLevel + 1);
+ }
+ images.at(mipmapLevel) = std::move(image);
- std::lock_guard<std::mutex> lock(mtx);
loaded = true;
}
+void Raster::bind(gl::ObjectStore& store,
+ gl::Config& config,
+ uint32_t unit,
+ Scaling newFilter,
+ MipMap newMipMap) {
+ bool updateFilter = false;
-void Raster::bind(bool linear, gl::ObjectStore& store) {
- if (!width || !height) {
- Log::Error(Event::OpenGL, "trying to bind texture without dimension");
- return;
+ if (!texture) {
+ if (images.empty()) {
+ Log::Error(Event::OpenGL, "trying to bind texture without images");
+ return;
+ } else {
+ upload(store, config, unit);
+ updateFilter = true;
+ }
+ } else {
+ if (config.texture[unit] != *texture) {
+ config.activeTexture = unit;
+ config.texture[unit] = *texture;
+ }
+ updateFilter = (filter != newFilter || mipmap != newMipMap);
}
- if (img.data && !texture) {
- upload(store);
- } else if (texture) {
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
- }
-
- GLint new_filter = linear ? GL_LINEAR : GL_NEAREST;
- if (new_filter != this->filter) {
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, new_filter));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, new_filter));
- filter = new_filter;
+ if (updateFilter) {
+ filter = newFilter;
+ mipmap = newMipMap;
+ config.activeTexture = unit;
+ MBGL_CHECK_ERROR(glTexParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ filter == Scaling::Linear
+ ? (mipmap == MipMap::Yes ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR)
+ : (mipmap == MipMap::Yes ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST)));
+ MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ filter == Scaling::Linear ? GL_LINEAR : GL_NEAREST));
}
}
-void Raster::upload(gl::ObjectStore& store) {
- if (img.data && !texture) {
- texture = texturePool.acquireTexture(store);
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
+void Raster::upload(gl::ObjectStore& store, gl::Config& config, uint32_t unit) {
+ if (!images.empty() && !texture) {
+ texture = store.createTexture();
+ config.activeTexture = unit;
+ config.texture[unit] = *texture;
#ifndef GL_ES_VERSION_2_0
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
+ MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, images.size()));
#endif
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
- MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.data.get()));
- img.data.reset();
+ GLint level = 0;
+ for (auto& img : images) {
+ assert(img.data.get());
+ MBGL_CHECK_ERROR(glTexImage2D(
+ GL_TEXTURE_2D, level++, GL_RGBA, static_cast<GLsizei>(img.width),
+ static_cast<GLsizei>(img.height), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.data.get()));
+ }
+ images.clear();
+ images.shrink_to_fit();
}
}
+
+} // namespace mbgl
diff --git a/src/mbgl/util/raster.hpp b/src/mbgl/util/raster.hpp
index b539032d81..34e7c67678 100644
--- a/src/mbgl/util/raster.hpp
+++ b/src/mbgl/util/raster.hpp
@@ -1,58 +1,51 @@
#pragma once
-#include <mbgl/gl/gl.hpp>
-#include <mbgl/gl/texture_pool.hpp>
+#include <mbgl/gl/object_store.hpp>
#include <mbgl/util/image.hpp>
-#include <mbgl/util/ptr.hpp>
-#include <mbgl/util/chrono.hpp>
#include <mbgl/util/optional.hpp>
-#include <mutex>
+#include <atomic>
namespace mbgl {
-class Raster : public std::enable_shared_from_this<Raster> {
+namespace gl {
+class Config;
+} // namespace gl
+class Raster {
public:
- Raster(gl::TexturePool&);
+ enum class MipMap : bool { No = false, Yes = true };
+ enum class Scaling : bool { Nearest = false, Linear = true };
// load image data
- void load(PremultipliedImage);
+ void load(PremultipliedImage, uint32_t mipmapLevel = 0);
// bind current texture
- void bind(bool linear, gl::ObjectStore&);
+ void bind(gl::ObjectStore&,
+ gl::Config&,
+ uint32_t unit,
+ Scaling = Scaling::Nearest,
+ MipMap = MipMap::No);
// uploads the texture if it hasn't been uploaded yet.
- void upload(gl::ObjectStore&);
+ void upload(gl::ObjectStore&, gl::Config&, uint32_t unit);
// loaded status
bool isLoaded() const;
-public:
- // loaded image dimensions
- GLsizei width = 0;
- GLsizei height = 0;
-
- // GL buffer object handle.
- mbgl::optional<gl::PooledTexture> texture;
-
- // texture opacity
- double opacity = 0;
-
private:
- mutable std::mutex mtx;
-
// raw pixels have been loaded
- bool loaded = false;
-
- // shared texture pool
- gl::TexturePool& texturePool;
+ std::atomic<bool> loaded { false };
- // min/mag filter
- GLint filter = 0;
+ // filters
+ Scaling filter = Scaling::Nearest;
+ MipMap mipmap = MipMap::No;
// the raw pixels
- PremultipliedImage img;
+ std::vector<PremultipliedImage> images;
+
+ // GL buffer object handle.
+ mbgl::optional<gl::UniqueTexture> texture;
};
} // namespace mbgl
diff --git a/src/mbgl/util/rect.hpp b/src/mbgl/util/rect.hpp
index 2b877db40d..f5937f5c94 100644
--- a/src/mbgl/util/rect.hpp
+++ b/src/mbgl/util/rect.hpp
@@ -4,21 +4,21 @@ namespace mbgl {
template <typename T>
struct Rect {
- inline Rect() = default;
- inline Rect(T x_, T y_, T w_, T h_) : x(x_), y(y_), w(w_), h(h_) {}
+ Rect() = default;
+ Rect(T x_, T y_, T w_, T h_) : x(x_), y(y_), w(w_), h(h_) {}
T x = 0, y = 0;
T w = 0, h = 0;
template <typename Number>
- inline Rect operator *(Number value) const {
+ Rect operator *(Number value) const {
return Rect(x * value, y * value, w * value, h * value);
}
template <typename R>
- inline bool operator==(const R& r) const {
+ bool operator==(const R& r) const {
return x == r.x && y == r.y && w == r.w && h == r.h;
}
- inline bool hasArea() const { return w != 0 && h != 0; }
+ bool hasArea() const { return w != 0 && h != 0; }
};
} // namespace mbgl
diff --git a/src/mbgl/util/stopwatch.cpp b/src/mbgl/util/stopwatch.cpp
index bbc6bfba0c..d588b79254 100644
--- a/src/mbgl/util/stopwatch.cpp
+++ b/src/mbgl/util/stopwatch.cpp
@@ -7,7 +7,8 @@
#include <iostream>
#include <atomic>
-using namespace mbgl::util;
+namespace mbgl {
+namespace util {
stopwatch::stopwatch(Event event_)
: event(event_), start(Clock::now()) {}
@@ -15,11 +16,11 @@ stopwatch::stopwatch(Event event_)
stopwatch::stopwatch(EventSeverity severity_, Event event_)
: severity(severity_), event(event_), start(Clock::now()) {}
-stopwatch::stopwatch(const std::string &name_, Event event_)
- : name(name_), event(event_), start(Clock::now()) {}
+stopwatch::stopwatch(std::string name_, Event event_)
+ : name(std::move(name_)), event(event_), start(Clock::now()) {}
-stopwatch::stopwatch(const std::string &name_, EventSeverity severity_, Event event_)
- : name(name_), severity(severity_), event(event_), start(Clock::now()) {}
+stopwatch::stopwatch(std::string name_, EventSeverity severity_, Event event_)
+ : name(std::move(name_)), severity(severity_), event(event_), start(Clock::now()) {}
void stopwatch::report(const std::string &name_) {
Duration duration = Clock::now() - start;
@@ -33,4 +34,8 @@ stopwatch::~stopwatch() {
report(name);
}
}
+
+} // namespace util
+} // namespace mbgl
+
#endif
diff --git a/src/mbgl/util/stopwatch.hpp b/src/mbgl/util/stopwatch.hpp
index 23086b1747..74cc2c412d 100644
--- a/src/mbgl/util/stopwatch.hpp
+++ b/src/mbgl/util/stopwatch.hpp
@@ -13,8 +13,8 @@ class stopwatch {
public:
stopwatch(Event event = Event::General);
stopwatch(EventSeverity severity, Event event = Event::General);
- stopwatch(const std::string &name, Event event = Event::General);
- stopwatch(const std::string &name, EventSeverity severity, Event event = Event::General);
+ stopwatch(std::string name, Event event = Event::General);
+ stopwatch(std::string name, EventSeverity severity, Event event = Event::General);
void report(const std::string &name);
~stopwatch();
@@ -26,12 +26,12 @@ private:
};
#else
class stopwatch {
- inline stopwatch(Event event = Event::General);
- inline stopwatch(EventSeverity severity, Event event = Event::General);
- inline stopwatch(const std::string &name, Event event = Event::General);
- inline stopwatch(const std::string &name, EventSeverity severity, Event event = Event::General);
- inline void report(const std::string &name) {}
- inline ~stopwatch() {}
+ stopwatch(Event event = Event::General);
+ stopwatch(EventSeverity severity, Event event = Event::General);
+ stopwatch(const std::string &name, Event event = Event::General);
+ stopwatch(const std::string &name, EventSeverity severity, Event event = Event::General);
+ void report(const std::string &name) {}
+ ~stopwatch() {}
};
#endif
} // namespace util
diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp
index c5f9d7338a..cd90e08049 100644
--- a/src/mbgl/util/thread.hpp
+++ b/src/mbgl/util/thread.hpp
@@ -6,7 +6,6 @@
#include <utility>
#include <functional>
-#include <mbgl/util/atomic.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/thread_context.hpp>
#include <mbgl/platform/platform.hpp>
@@ -95,13 +94,7 @@ Thread<Object>::Thread(const ThreadContext& context, Args&&... args) {
std::tuple<Args...> params = std::forward_as_tuple(::std::forward<Args>(args)...);
thread = std::thread([&] {
-#if defined(__APPLE__)
- pthread_setname_np(context.name.c_str());
-#elif defined(__GLIBC__) && defined(__GLIBC_PREREQ)
-#if __GLIBC_PREREQ(2, 12)
- pthread_setname_np(pthread_self(), context.name.c_str());
-#endif
-#endif
+ platform::setCurrentThreadName(context.name);
if (context.priority == ThreadPriority::Low) {
platform::makeThreadLowPriority();
diff --git a/src/mbgl/util/thread_context.cpp b/src/mbgl/util/thread_context.cpp
index f728e32df7..fe64c2a686 100644
--- a/src/mbgl/util/thread_context.cpp
+++ b/src/mbgl/util/thread_context.cpp
@@ -1,10 +1,11 @@
#include <mbgl/util/thread_context.hpp>
+#include <utility>
namespace mbgl {
namespace util {
-ThreadContext::ThreadContext(const std::string& name_, ThreadPriority priority_)
- : name(name_),
+ThreadContext::ThreadContext(std::string name_, ThreadPriority priority_)
+ : name(std::move(name_)),
priority(priority_) {
}
diff --git a/src/mbgl/util/thread_context.hpp b/src/mbgl/util/thread_context.hpp
index 60b32b3b2a..a51dede404 100644
--- a/src/mbgl/util/thread_context.hpp
+++ b/src/mbgl/util/thread_context.hpp
@@ -12,7 +12,7 @@ enum class ThreadPriority : bool {
struct ThreadContext {
public:
- ThreadContext(const std::string& name, ThreadPriority priority = ThreadPriority::Regular);
+ ThreadContext(std::string name, ThreadPriority priority = ThreadPriority::Regular);
std::string name;
ThreadPriority priority;
diff --git a/src/mbgl/util/thread_local.hpp b/src/mbgl/util/thread_local.hpp
index c3364c5d42..67e3842ec6 100644
--- a/src/mbgl/util/thread_local.hpp
+++ b/src/mbgl/util/thread_local.hpp
@@ -12,12 +12,12 @@ namespace util {
template <class T>
class ThreadLocal : public noncopyable {
public:
- inline ThreadLocal(T* val) {
+ ThreadLocal(T* val) {
ThreadLocal();
set(val);
}
- inline ThreadLocal() {
+ ThreadLocal() {
int ret = pthread_key_create(&key, [](void *ptr) {
delete reinterpret_cast<T *>(ptr);
});
@@ -27,13 +27,13 @@ public:
}
}
- inline ~ThreadLocal() {
+ ~ThreadLocal() {
if (pthread_key_delete(key)) {
throw std::runtime_error("Failed to delete local storage key.");
}
}
- inline T* get() {
+ T* get() {
T* ret = reinterpret_cast<T*>(pthread_getspecific(key));
if (!ret) {
return nullptr;
@@ -42,7 +42,7 @@ public:
return ret;
}
- inline void set(T* ptr) {
+ void set(T* ptr) {
if (pthread_setspecific(key, ptr)) {
throw std::runtime_error("Failed to set local storage.");
}
diff --git a/src/mbgl/util/tile_coordinate.cpp b/src/mbgl/util/tile_coordinate.cpp
deleted file mode 100644
index d9a0ea352c..0000000000
--- a/src/mbgl/util/tile_coordinate.cpp
+++ /dev/null
@@ -1 +0,0 @@
-#include <mbgl/util/tile_coordinate.hpp>
diff --git a/src/mbgl/util/tileset.hpp b/src/mbgl/util/tileset.hpp
deleted file mode 100644
index 972fc51f8c..0000000000
--- a/src/mbgl/util/tileset.hpp
+++ /dev/null
@@ -1,24 +0,0 @@
-#pragma once
-
-#include <mbgl/util/constants.hpp>
-#include <mbgl/util/geo.hpp>
-
-#include <array>
-#include <vector>
-#include <string>
-#include <cstdint>
-
-namespace mbgl {
-
-class Tileset {
-public:
- std::vector<std::string> tiles;
- uint8_t minZoom = 0;
- uint8_t maxZoom = 22;
- std::string attribution;
- LatLng center;
- double zoom = 0;
- LatLngBounds bounds = LatLngBounds::world();
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/util/utf.hpp b/src/mbgl/util/utf.hpp
index 02aabfc4c2..560ca3ba7f 100644
--- a/src/mbgl/util/utf.hpp
+++ b/src/mbgl/util/utf.hpp
@@ -17,5 +17,5 @@ class utf8_to_utf32 {
}
};
-} // namespace mbgl
} // namespace util
+} // namespace mbgl
diff --git a/src/mbgl/util/version_info.cpp b/src/mbgl/util/version_info.cpp
index c545ddcc40..f0fb139bca 100644
--- a/src/mbgl/util/version_info.cpp
+++ b/src/mbgl/util/version_info.cpp
@@ -11,4 +11,4 @@ const char *string = MBGL_VERSION_STRING;
const unsigned int number = MBGL_VERSION;
} // namespace version
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/src/mbgl/util/work_task.cpp b/src/mbgl/util/work_task.cpp
deleted file mode 100644
index e69de29bb2..0000000000
--- a/src/mbgl/util/work_task.cpp
+++ /dev/null
diff --git a/src/mbgl/util/worker.cpp b/src/mbgl/util/worker.cpp
index 2bc545c704..50ecb93c02 100644
--- a/src/mbgl/util/worker.cpp
+++ b/src/mbgl/util/worker.cpp
@@ -3,7 +3,7 @@
#include <mbgl/util/work_request.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/renderer/raster_bucket.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/style/layer.hpp>
#include <mbgl/text/collision_tile.hpp>
@@ -31,11 +31,11 @@ public:
void parseGeometryTile(TileWorker* worker,
std::vector<std::unique_ptr<style::Layer>> layers,
- std::unique_ptr<GeometryTile> tile,
+ std::unique_ptr<GeometryTileData> tileData,
PlacementConfig config,
std::function<void(TileParseResult)> callback) {
try {
- callback(worker->parseAllLayers(std::move(layers), std::move(tile), config));
+ callback(worker->parseAllLayers(std::move(layers), std::move(tileData), config));
} catch (...) {
callback(std::current_exception());
}
@@ -80,12 +80,12 @@ Worker::parseRasterTile(std::unique_ptr<RasterBucket> bucket,
std::unique_ptr<AsyncRequest>
Worker::parseGeometryTile(TileWorker& worker,
std::vector<std::unique_ptr<style::Layer>> layers,
- std::unique_ptr<GeometryTile> tile,
+ std::unique_ptr<GeometryTileData> tileData,
PlacementConfig config,
std::function<void(TileParseResult)> callback) {
current = (current + 1) % threads.size();
return threads[current]->invokeWithCallback(&Worker::Impl::parseGeometryTile, callback, &worker,
- std::move(layers), std::move(tile), config);
+ std::move(layers), std::move(tileData), config);
}
std::unique_ptr<AsyncRequest>
diff --git a/src/mbgl/util/worker.hpp b/src/mbgl/util/worker.hpp
index 678dfaedb3..5ab86d1b9e 100644
--- a/src/mbgl/util/worker.hpp
+++ b/src/mbgl/util/worker.hpp
@@ -41,7 +41,7 @@ public:
Request parseGeometryTile(TileWorker&,
std::vector<std::unique_ptr<style::Layer>>,
- std::unique_ptr<GeometryTile>,
+ std::unique_ptr<GeometryTileData>,
PlacementConfig,
std::function<void(TileParseResult)> callback);