summaryrefslogtreecommitdiff
path: root/src/mbgl/algorithm/update_renderables.hpp
blob: 1f58075a58b04fa88b8e6a467dbfddfc8e051cdf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#pragma once

#include <mbgl/tile/tile_id.hpp>

#include <set>

namespace mbgl {
namespace algorithm {

template <typename GetTileDataFn,
          typename CreateTileDataFn,
          typename RetainTileDataFn,
          typename RenderTileFn,
          typename IdealTileIDs,
          typename SourceInfo>
void updateRenderables(GetTileDataFn getTileData,
                       CreateTileDataFn createTileData,
                       RetainTileDataFn retainTileData,
                       RenderTileFn renderTile,
                       const IdealTileIDs& idealTileIDs,
                       const SourceInfo& info,
                       const uint8_t dataTileZoom) {
    std::set<UnwrappedTileID> checked;
    bool covered;
    int32_t overscaledZ;

    // 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(dataTileZoom >= idealRenderTileID.canonical.z);

        const OverscaledTileID idealDataTileID(dataTileZoom, idealRenderTileID.canonical);
        auto data = getTileData(idealDataTileID);
        if (!data) {
            data = createTileData(idealDataTileID, true);
            assert(data);
        }

        // if (source has the tile and bucket is loaded) {
        if (data->isRenderable()) {
            retainTileData(*data);
            renderTile(idealRenderTileID, *data);
        } else {
            // The tile isn't loaded yet, but retain it anyway because it's an ideal tile.
            retainTileData(*data);
            covered = true;
            overscaledZ = dataTileZoom + 1;
            if (overscaledZ > info.maxZoom) {
                // We're looking for an overzoomed child tile.
                const auto childDataTileID = idealDataTileID.scaledTo(overscaledZ);
                data = getTileData(childDataTileID);
                if (data && data->isRenderable()) {
                    retainTileData(*data);
                    renderTile(idealRenderTileID, *data);
                } else {
                    covered = false;
                }
            } else {
                // Check all four actual child tiles.
                for (const auto& childTileID : idealDataTileID.canonical.children()) {
                    const OverscaledTileID childDataTileID(overscaledZ, childTileID);
                    data = getTileData(childDataTileID);
                    if (data && data->isRenderable()) {
                        retainTileData(*data);
                        renderTile(childDataTileID.unwrapTo(idealRenderTileID.wrap), *data);
                    } else {
                        // At least one child tile doesn't exist, so we are going to look for
                        // parents as well.
                        covered = false;
                    }
                }
            }

            if (!covered) {
                // We couldn't find child tiles that entirely cover the ideal tile.
                for (overscaledZ = dataTileZoom - 1; overscaledZ >= info.minZoom; --overscaledZ) {
                    const auto parentDataTileID = idealDataTileID.scaledTo(overscaledZ);
                    const auto parentRenderTileID =
                        parentDataTileID.unwrapTo(idealRenderTileID.wrap);

                    if (checked.find(parentRenderTileID) != checked.end()) {
                        // Break parent tile ascent, this route has been checked by another child
                        // tile before.
                        break;
                    } else {
                        checked.emplace(parentRenderTileID);
                    }

                    data = getTileData(parentDataTileID);
                    if (data && data->isRenderable()) {
                        retainTileData(*data);
                        renderTile(parentRenderTileID, *data);
                        // Break parent tile ascent, since we found one.
                        break;
                    }
                }
            }
        }
    }
}

} // namespace algorithm
} // namespace mbgl