diff options
Diffstat (limited to 'src/mbgl/tile/vector_tile_data.cpp')
-rw-r--r-- | src/mbgl/tile/vector_tile_data.cpp | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/mbgl/tile/vector_tile_data.cpp b/src/mbgl/tile/vector_tile_data.cpp new file mode 100644 index 0000000000..d2eecab975 --- /dev/null +++ b/src/mbgl/tile/vector_tile_data.cpp @@ -0,0 +1,183 @@ +#include <mbgl/tile/vector_tile_data.hpp> +#include <mbgl/tile/geometry_tile.hpp> +#include <mbgl/style/style_layer.hpp> +#include <mbgl/util/worker.hpp> +#include <mbgl/util/work_request.hpp> +#include <mbgl/style/style.hpp> +#include <mbgl/storage/file_source.hpp> + +namespace mbgl { + +VectorTileData::VectorTileData(const TileID& id_, + std::unique_ptr<GeometryTileMonitor> monitor_, + std::string sourceID, + 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, + state, + mode_), + monitor(std::move(monitor_)) +{ + state = State::loading; + tileRequest = monitor->monitorTile([callback, this](std::exception_ptr err, + std::unique_ptr<GeometryTile> tile, + optional<SystemTimePoint> modified_, + optional<SystemTimePoint> 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(); + state = State::parsed; + buckets.clear(); + callback(err); + return; + } + + if (state == State::loading) { + state = State::loaded; + } else if (isReady()) { + state = State::partial; + } + + // 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(); + if (state == State::obsolete) { + return; + } + + std::exception_ptr error; + if (result.is<TileParseResultBuckets>()) { + auto& resultBuckets = result.get<TileParseResultBuckets>(); + state = resultBuckets.state; + + // 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); + + } else { + error = result.get<std::exception_ptr>(); + state = State::obsolete; + } + + 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(); + if (state == State::obsolete) { + return; + } + + std::exception_ptr error; + if (result.is<TileParseResultBuckets>()) { + auto& resultBuckets = result.get<TileParseResultBuckets>(); + state = resultBuckets.state; + + // 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; + + } else { + error = result.get<std::exception_ptr>(); + state = State::obsolete; + } + + callback(error); + }); + + return true; +} + +Bucket* VectorTileData::getBucket(const StyleLayer& layer) { + const auto it = buckets.find(layer.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] { + 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(); + } + + // 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::cancel() { + state = State::obsolete; + tileRequest.reset(); + workRequest.reset(); +} + +} // namespace mbgl |