Files
MapLibreParticleLab/src/mbgl/algorithm/update_renderables.hpp
Chris Loer a432a289a3 [core] Change OverscaledTileID to also include a "wrap" value.
This prevents TilePyramid from sharing wrapped copies of tiles.
This is necessary because two wrapped tiles no longer share the same CollisionTile.
2017-07-11 09:10:24 -07:00

122 lines
5.0 KiB
C++

#pragma once
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/util/range.hpp>
#include <mbgl/storage/resource.hpp>
#include <unordered_set>
namespace mbgl {
namespace algorithm {
template <typename GetTileFn,
typename CreateTileFn,
typename RetainTileFn,
typename RenderTileFn,
typename IdealTileIDs>
void updateRenderables(GetTileFn getTile,
CreateTileFn createTile,
RetainTileFn retainTile,
RenderTileFn renderTile,
const IdealTileIDs& idealTileIDs,
const Range<uint8_t>& zoomRange,
const uint8_t dataTileZoom) {
std::unordered_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 >= zoomRange.min);
assert(idealRenderTileID.canonical.z <= zoomRange.max);
assert(dataTileZoom >= idealRenderTileID.canonical.z);
const OverscaledTileID idealDataTileID(dataTileZoom, idealRenderTileID.wrap, idealRenderTileID.canonical);
auto tile = getTile(idealDataTileID);
if (!tile) {
tile = createTile(idealDataTileID);
assert(tile);
}
// if (source has the tile and bucket is loaded) {
if (tile->isRenderable()) {
retainTile(*tile, Resource::Necessity::Required);
renderTile(idealRenderTileID, *tile);
} else {
// We are now attempting to load child and parent tiles.
bool parentHasTriedOptional = tile->hasTriedOptional();
bool parentIsLoaded = tile->isLoaded();
// The tile isn't loaded yet, but retain it anyway because it's an ideal tile.
retainTile(*tile, Resource::Necessity::Required);
covered = true;
overscaledZ = dataTileZoom + 1;
if (overscaledZ > zoomRange.max) {
// We're looking for an overzoomed child tile.
const auto childDataTileID = idealDataTileID.scaledTo(overscaledZ);
tile = getTile(childDataTileID);
if (tile && tile->isRenderable()) {
retainTile(*tile, Resource::Necessity::Optional);
renderTile(idealRenderTileID, *tile);
} else {
covered = false;
}
} else {
// Check all four actual child tiles.
for (const auto& childTileID : idealDataTileID.canonical.children()) {
const OverscaledTileID childDataTileID(overscaledZ, idealRenderTileID.wrap, childTileID);
tile = getTile(childDataTileID);
if (tile && tile->isRenderable()) {
retainTile(*tile, Resource::Necessity::Optional);
renderTile(childDataTileID.toUnwrapped(), *tile);
} 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 >= zoomRange.min; --overscaledZ) {
const auto parentDataTileID = idealDataTileID.scaledTo(overscaledZ);
const auto parentRenderTileID = parentDataTileID.toUnwrapped();
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);
}
tile = getTile(parentDataTileID);
if (!tile && (parentHasTriedOptional || parentIsLoaded)) {
tile = createTile(parentDataTileID);
}
if (tile) {
retainTile(*tile, parentIsLoaded ? Resource::Necessity::Required
: Resource::Necessity::Optional);
// Save the current values, since they're the parent of the next iteration
// of the parent tile ascent loop.
parentHasTriedOptional = tile->hasTriedOptional();
parentIsLoaded = tile->isLoaded();
if (tile->isRenderable()) {
renderTile(parentRenderTileID, *tile);
// Break parent tile ascent, since we found one.
break;
}
}
}
}
}
}
}
} // namespace algorithm
} // namespace mbgl