1 #pragma once
2
3 #include <mbgl/tile/tile_id.hpp>
4 #include <mbgl/tile/tile_necessity.hpp>
5 #include <mbgl/util/range.hpp>
6
7 #include <unordered_set>
8
9 namespace mbgl {
10 namespace algorithm {
11
12 template <typename GetTileFn,
13 typename CreateTileFn,
14 typename RetainTileFn,
15 typename RenderTileFn,
16 typename IdealTileIDs>
updateRenderables(GetTileFn getTile,CreateTileFn createTile,RetainTileFn retainTile,RenderTileFn renderTile,const IdealTileIDs & idealTileIDs,const Range<uint8_t> & zoomRange,const uint8_t dataTileZoom)17 void updateRenderables(GetTileFn getTile,
18 CreateTileFn createTile,
19 RetainTileFn retainTile,
20 RenderTileFn renderTile,
21 const IdealTileIDs& idealTileIDs,
22 const Range<uint8_t>& zoomRange,
23 const uint8_t dataTileZoom) {
24 std::unordered_set<UnwrappedTileID> checked;
25 bool covered;
26 int32_t overscaledZ;
27
28 // for (all in the set of ideal tiles of the source) {
29 for (const auto& idealRenderTileID : idealTileIDs) {
30 assert(idealRenderTileID.canonical.z >= zoomRange.min);
31 assert(idealRenderTileID.canonical.z <= zoomRange.max);
32 assert(dataTileZoom >= idealRenderTileID.canonical.z);
33
34 const OverscaledTileID idealDataTileID(dataTileZoom, idealRenderTileID.wrap, idealRenderTileID.canonical);
35 auto tile = getTile(idealDataTileID);
36 if (!tile) {
37 tile = createTile(idealDataTileID);
38 // For source types where TileJSON.bounds is set, tiles outside the
39 // bounds are not created
40 if(tile == nullptr) {
41 continue;
42 }
43 }
44
45 // if (source has the tile and bucket is loaded) {
46 if (tile->isRenderable()) {
47 retainTile(*tile, TileNecessity::Required);
48 renderTile(idealRenderTileID, *tile);
49 } else {
50 // We are now attempting to load child and parent tiles.
51 bool parentHasTriedOptional = tile->hasTriedCache();
52 bool parentIsLoaded = tile->isLoaded();
53
54 // The tile isn't loaded yet, but retain it anyway because it's an ideal tile.
55 retainTile(*tile, TileNecessity::Required);
56 covered = true;
57 overscaledZ = dataTileZoom + 1;
58 if (overscaledZ > zoomRange.max) {
59 // We're looking for an overzoomed child tile.
60 const auto childDataTileID = idealDataTileID.scaledTo(overscaledZ);
61 tile = getTile(childDataTileID);
62 if (tile && tile->isRenderable()) {
63 retainTile(*tile, TileNecessity::Optional);
64 renderTile(idealRenderTileID, *tile);
65 } else {
66 covered = false;
67 }
68 } else {
69 // Check all four actual child tiles.
70 for (const auto& childTileID : idealDataTileID.canonical.children()) {
71 const OverscaledTileID childDataTileID(overscaledZ, idealRenderTileID.wrap, childTileID);
72 tile = getTile(childDataTileID);
73 if (tile && tile->isRenderable()) {
74 retainTile(*tile, TileNecessity::Optional);
75 renderTile(childDataTileID.toUnwrapped(), *tile);
76 } else {
77 // At least one child tile doesn't exist, so we are going to look for
78 // parents as well.
79 covered = false;
80 }
81 }
82 }
83
84 if (!covered) {
85 // We couldn't find child tiles that entirely cover the ideal tile.
86 for (overscaledZ = dataTileZoom - 1; overscaledZ >= zoomRange.min; --overscaledZ) {
87 const auto parentDataTileID = idealDataTileID.scaledTo(overscaledZ);
88 const auto parentRenderTileID = parentDataTileID.toUnwrapped();
89
90 if (checked.find(parentRenderTileID) != checked.end()) {
91 // Break parent tile ascent, this route has been checked by another child
92 // tile before.
93 break;
94 } else {
95 checked.emplace(parentRenderTileID);
96 }
97
98 tile = getTile(parentDataTileID);
99 if (!tile && (parentHasTriedOptional || parentIsLoaded)) {
100 tile = createTile(parentDataTileID);
101 }
102
103 if (tile) {
104 if (!parentIsLoaded) {
105 // We haven't completed loading the child, so we only do an optional
106 // (cache) request in an attempt to quickly load data that we can show.
107 retainTile(*tile, TileNecessity::Optional);
108 } else {
109 // Now that we've checked the child and know for sure that we can't load
110 // it, we attempt to load the parent from the network.
111 retainTile(*tile, TileNecessity::Required);
112 }
113
114 // Save the current values, since they're the parent of the next iteration
115 // of the parent tile ascent loop.
116 parentHasTriedOptional = tile->hasTriedCache();
117 parentIsLoaded = tile->isLoaded();
118
119 if (tile->isRenderable()) {
120 renderTile(parentRenderTileID, *tile);
121 // Break parent tile ascent, since we found one.
122 break;
123 }
124 }
125 }
126 }
127 }
128 }
129 }
130
131 } // namespace algorithm
132 } // namespace mbgl
133