diff options
author | Thiago Marcos P. Santos <tmpsantos@gmail.com> | 2017-10-31 13:10:01 +0200 |
---|---|---|
committer | Thiago Marcos P. Santos <tmpsantos@gmail.com> | 2017-11-01 18:06:36 +0200 |
commit | 688540a44d7977208b606b02376edc7d87854db8 (patch) | |
tree | 51a4335ccbd182263e8d7b5793703cf69ce74d1e /src | |
parent | 90a7cf87a32f6787e57e3852ac9d3015d8112621 (diff) | |
download | qtlocation-mapboxgl-688540a44d7977208b606b02376edc7d87854db8.tar.gz |
Bump Mapbox GL Native
mapbox-gl-native @ 0ef7b7154f6d4498077a83db5c486c61bc34938c
Diffstat (limited to 'src')
35 files changed, 1516 insertions, 1261 deletions
diff --git a/src/mbgl/annotation/render_annotation_source.cpp b/src/mbgl/annotation/render_annotation_source.cpp index 34fb576727..ba80be0da0 100644 --- a/src/mbgl/annotation/render_annotation_source.cpp +++ b/src/mbgl/annotation/render_annotation_source.cpp @@ -38,7 +38,9 @@ void RenderAnnotationSource::update(Immutable<style::Source::Impl> baseImpl_, parameters, SourceType::Annotations, util::tileSize, - { 0, util::DEFAULT_MAX_ZOOM }, + // Zoom level 16 is typically sufficient for annotations. + // See https://github.com/mapbox/mapbox-gl-native/issues/10197 + { 0, 16 }, [&] (const OverscaledTileID& tileID) { return std::make_unique<AnnotationTile>(tileID, parameters); }); diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index d0c538efb0..e04f134f39 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -248,7 +248,14 @@ UniqueTexture Context::createTexture() { } bool Context::supportsVertexArrays() const { - return vertexArray && + static bool blacklisted = []() { + // Blacklist Adreno 3xx as it crashes on glBuffer(Sub)Data + const std::string renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); + return renderer.find("Adreno (TM) 3") != std::string::npos; + }(); + + return !blacklisted && + vertexArray && vertexArray->genVertexArrays && vertexArray->bindVertexArray && vertexArray->deleteVertexArrays; @@ -583,13 +590,14 @@ void Context::setDirtyState() { void Context::clear(optional<mbgl::Color> color, optional<float> depth, - optional<int32_t> stencil) { + optional<int32_t> stencil, + optional<ColorMode::Mask> colorMask_) { GLbitfield mask = 0; if (color) { mask |= GL_COLOR_BUFFER_BIT; clearColor = *color; - colorMask = { true, true, true, true }; + colorMask = colorMask_ ? *colorMask_ : value::ColorMask::Default; } if (depth) { @@ -605,6 +613,10 @@ void Context::clear(optional<mbgl::Color> color, } MBGL_CHECK_ERROR(glClear(mask)); + + if (colorMask_) { + colorMask = value::ColorMask::Default; + } } #if not MBGL_USE_GLES2 diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 528113cbba..2d650e7ecb 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -146,7 +146,8 @@ public: void clear(optional<mbgl::Color> color, optional<float> depth, - optional<int32_t> stencil); + optional<int32_t> stencil, + optional<ColorMode::Mask> colorMask = value::ColorMask::Default); void setDrawMode(const Points&); void setDrawMode(const Lines&); diff --git a/src/mbgl/gl/gl.hpp b/src/mbgl/gl/gl.hpp index 3e21731330..976b7d2f74 100644 --- a/src/mbgl/gl/gl.hpp +++ b/src/mbgl/gl/gl.hpp @@ -1,36 +1,10 @@ #pragma once +#include <mbgl/gl/gl_impl.hpp> + #include <stdexcept> #include <limits> -#if __APPLE__ - #include "TargetConditionals.h" - #if TARGET_OS_IPHONE - #include <OpenGLES/ES2/gl.h> - #include <OpenGLES/ES2/glext.h> - #elif TARGET_IPHONE_SIMULATOR - #include <OpenGLES/ES2/gl.h> - #include <OpenGLES/ES2/glext.h> - #elif TARGET_OS_MAC - #include <OpenGL/OpenGL.h> - #include <OpenGL/gl.h> - #include <OpenGL/glext.h> - #else - #error Unsupported Apple platform - #endif -#elif __ANDROID__ || MBGL_USE_GLES2 - #define GL_GLEXT_PROTOTYPES - #include <GLES2/gl2.h> - #include <GLES2/gl2ext.h> -#elif __QT__ && QT_VERSION >= 0x050000 - #define GL_GLEXT_PROTOTYPES - #include <QtGui/qopengl.h> -#else - #define GL_GLEXT_PROTOTYPES - #include <GL/gl.h> - #include <GL/glext.h> -#endif - namespace mbgl { namespace gl { diff --git a/src/mbgl/map/update.hpp b/src/mbgl/map/update.hpp deleted file mode 100644 index 057720a5c9..0000000000 --- a/src/mbgl/map/update.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include <mbgl/util/traits.hpp> -#include <mbgl/util/util.hpp> - -namespace mbgl { - -enum class Update { - Nothing = 0, - Repaint = 1 << 0, - AnnotationData = 1 << 7 -}; - -MBGL_CONSTEXPR Update operator|(Update lhs, Update rhs) { - return Update(mbgl::underlying_type(lhs) | mbgl::underlying_type(rhs)); -} - -MBGL_CONSTEXPR Update& operator|=(Update& lhs, const Update& rhs) { - return (lhs = lhs | rhs); -} - -MBGL_CONSTEXPR bool operator& (Update lhs, Update rhs) { - return mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs); -} - -} // namespace mbgl diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp index 4a2c2c6f12..60f5af4e9a 100644 --- a/src/mbgl/renderer/paint_parameters.hpp +++ b/src/mbgl/renderer/paint_parameters.hpp @@ -2,6 +2,7 @@ #include <mbgl/renderer/render_pass.hpp> #include <mbgl/renderer/render_light.hpp> +#include <mbgl/renderer/mode.hpp> #include <mbgl/map/mode.hpp> #include <mbgl/gl/depth_mode.hpp> #include <mbgl/gl/stencil_mode.hpp> diff --git a/src/mbgl/renderer/render_item.hpp b/src/mbgl/renderer/render_item.hpp deleted file mode 100644 index 4bf5629263..0000000000 --- a/src/mbgl/renderer/render_item.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include <mbgl/util/color.hpp> - -#include <unordered_set> -#include <vector> - -namespace mbgl { - -class RenderLayer; -class RenderSource; -class RenderTile; -class Bucket; - -namespace style { -} // namespace style - -class RenderItem { -public: - RenderItem(RenderLayer& layer_, - RenderSource* renderSource_) - : layer(layer_), source(renderSource_) { - } - - RenderLayer& layer; - RenderSource* source; -}; - -class RenderData { -public: - Color backgroundColor; - std::unordered_set<RenderSource*> sources; - std::vector<RenderItem> order; -}; - -} // namespace mbgl diff --git a/src/mbgl/renderer/render_style.cpp b/src/mbgl/renderer/render_style.cpp deleted file mode 100644 index 3d95b12bc4..0000000000 --- a/src/mbgl/renderer/render_style.cpp +++ /dev/null @@ -1,449 +0,0 @@ -#include <mbgl/renderer/render_style.hpp> -#include <mbgl/renderer/render_style_observer.hpp> -#include <mbgl/renderer/update_parameters.hpp> -#include <mbgl/renderer/transition_parameters.hpp> -#include <mbgl/renderer/property_evaluation_parameters.hpp> -#include <mbgl/renderer/tile_parameters.hpp> -#include <mbgl/renderer/render_source.hpp> -#include <mbgl/renderer/render_item.hpp> -#include <mbgl/renderer/render_tile.hpp> -#include <mbgl/renderer/layers/render_background_layer.hpp> -#include <mbgl/renderer/layers/render_circle_layer.hpp> -#include <mbgl/renderer/layers/render_custom_layer.hpp> -#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp> -#include <mbgl/renderer/layers/render_fill_layer.hpp> -#include <mbgl/renderer/layers/render_line_layer.hpp> -#include <mbgl/renderer/layers/render_raster_layer.hpp> -#include <mbgl/renderer/layers/render_symbol_layer.hpp> -#include <mbgl/renderer/backend_scope.hpp> -#include <mbgl/renderer/style_diff.hpp> -#include <mbgl/renderer/image_manager.hpp> -#include <mbgl/renderer/query.hpp> -#include <mbgl/style/style.hpp> -#include <mbgl/style/source_impl.hpp> -#include <mbgl/style/transition_options.hpp> -#include <mbgl/sprite/sprite_loader.hpp> -#include <mbgl/text/glyph_manager.hpp> -#include <mbgl/geometry/line_atlas.hpp> -#include <mbgl/tile/tile.hpp> -#include <mbgl/util/math.hpp> -#include <mbgl/util/string.hpp> -#include <mbgl/util/logging.hpp> - -namespace mbgl { - -using namespace style; - -RenderStyleObserver nullObserver; - -RenderStyle::RenderStyle(Scheduler& scheduler_, FileSource& fileSource_) - : scheduler(scheduler_), - fileSource(fileSource_), - glyphManager(std::make_unique<GlyphManager>(fileSource)), - imageManager(std::make_unique<ImageManager>()), - lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })), - imageImpls(makeMutable<std::vector<Immutable<style::Image::Impl>>>()), - sourceImpls(makeMutable<std::vector<Immutable<style::Source::Impl>>>()), - layerImpls(makeMutable<std::vector<Immutable<style::Layer::Impl>>>()), - renderLight(makeMutable<Light::Impl>()), - observer(&nullObserver) { - glyphManager->setObserver(this); -} - -RenderStyle::~RenderStyle() { - assert(BackendScope::exists()); // Required for custom layers. -} - -void RenderStyle::setObserver(RenderStyleObserver* observer_) { - observer = observer_; -} - -std::vector<const RenderLayer*> RenderStyle::getRenderLayers() const { - std::vector<const RenderLayer*> result; - result.reserve(renderLayers.size()); - for (const auto& layer : *layerImpls) { - result.push_back(getRenderLayer(layer->id)); - } - return result; -} - -RenderLayer* RenderStyle::getRenderLayer(const std::string& id) { - auto it = renderLayers.find(id); - return it != renderLayers.end() ? it->second.get() : nullptr; -} - -const RenderLayer* RenderStyle::getRenderLayer(const std::string& id) const { - auto it = renderLayers.find(id); - return it != renderLayers.end() ? it->second.get() : nullptr; -} - -const RenderLight& RenderStyle::getRenderLight() const { - return renderLight; -} - -void RenderStyle::update(const UpdateParameters& parameters) { - assert(BackendScope::exists()); // Required for custom layers. - - const bool zoomChanged = zoomHistory.update(parameters.transformState.getZoom(), parameters.timePoint); - - const TransitionParameters transitionParameters { - parameters.timePoint, - parameters.mode == MapMode::Continuous ? parameters.transitionOptions : TransitionOptions() - }; - - const PropertyEvaluationParameters evaluationParameters { - zoomHistory, - parameters.timePoint, - parameters.mode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Duration::zero() - }; - - const TileParameters tileParameters { - parameters.pixelRatio, - parameters.debugOptions, - parameters.transformState, - parameters.scheduler, - parameters.fileSource, - parameters.mode, - parameters.annotationManager, - *imageManager, - *glyphManager, - parameters.prefetchZoomDelta - }; - - glyphManager->setURL(parameters.glyphURL); - - // Update light. - const bool lightChanged = renderLight.impl != parameters.light; - - if (lightChanged) { - renderLight.impl = parameters.light; - renderLight.transition(transitionParameters); - } - - if (lightChanged || zoomChanged || renderLight.hasTransition()) { - renderLight.evaluate(evaluationParameters); - } - - - const ImageDifference imageDiff = diffImages(imageImpls, parameters.images); - imageImpls = parameters.images; - - // Remove removed images from sprite atlas. - for (const auto& entry : imageDiff.removed) { - imageManager->removeImage(entry.first); - } - - // Add added images to sprite atlas. - for (const auto& entry : imageDiff.added) { - imageManager->addImage(entry.second); - } - - // Update changed images. - for (const auto& entry : imageDiff.changed) { - imageManager->updateImage(entry.second.after); - } - - imageManager->setLoaded(parameters.spriteLoaded); - - - const LayerDifference layerDiff = diffLayers(layerImpls, parameters.layers); - layerImpls = parameters.layers; - - // Remove render layers for removed layers. - for (const auto& entry : layerDiff.removed) { - renderLayers.erase(entry.first); - } - - // Create render layers for newly added layers. - for (const auto& entry : layerDiff.added) { - renderLayers.emplace(entry.first, RenderLayer::create(entry.second)); - } - - // Update render layers for changed layers. - for (const auto& entry : layerDiff.changed) { - renderLayers.at(entry.first)->setImpl(entry.second.after); - } - - // Update layers for class and zoom changes. - for (const auto& entry : renderLayers) { - RenderLayer& layer = *entry.second; - const bool layerAdded = layerDiff.added.count(entry.first); - const bool layerChanged = layerDiff.changed.count(entry.first); - - if (layerAdded || layerChanged) { - layer.transition(transitionParameters); - } - - if (layerAdded || layerChanged || zoomChanged || layer.hasTransition()) { - layer.evaluate(evaluationParameters); - } - } - - - const SourceDifference sourceDiff = diffSources(sourceImpls, parameters.sources); - sourceImpls = parameters.sources; - - // Remove render layers for removed sources. - for (const auto& entry : sourceDiff.removed) { - renderSources.erase(entry.first); - } - - // Create render sources for newly added sources. - for (const auto& entry : sourceDiff.added) { - std::unique_ptr<RenderSource> renderSource = RenderSource::create(entry.second); - renderSource->setObserver(this); - renderSources.emplace(entry.first, std::move(renderSource)); - } - - // Update all sources. - for (const auto& source : *sourceImpls) { - std::vector<Immutable<Layer::Impl>> filteredLayers; - bool needsRendering = false; - bool needsRelayout = false; - - for (const auto& layer : *layerImpls) { - if (layer->type == LayerType::Background || - layer->type == LayerType::Custom || - layer->source != source->id) { - continue; - } - - if (!needsRendering && getRenderLayer(layer->id)->needsRendering(zoomHistory.lastZoom)) { - needsRendering = true; - } - - if (!needsRelayout && ( - hasLayoutDifference(layerDiff, layer->id) || - !imageDiff.added.empty() || - !imageDiff.removed.empty() || - !imageDiff.changed.empty())) { - needsRelayout = true; - } - - filteredLayers.push_back(layer); - } - - renderSources.at(source->id)->update(source, - filteredLayers, - needsRendering, - needsRelayout, - tileParameters); - } -} - -RenderSource* RenderStyle::getRenderSource(const std::string& id) const { - auto it = renderSources.find(id); - return it != renderSources.end() ? it->second.get() : nullptr; -} - -bool RenderStyle::hasTransitions() const { - if (renderLight.hasTransition()) { - return true; - } - - for (const auto& entry : renderLayers) { - if (entry.second->hasTransition()) { - return true; - } - } - - return false; -} - -bool RenderStyle::isLoaded() const { - for (const auto& entry: renderSources) { - if (!entry.second->isLoaded()) { - return false; - } - } - - if (!imageManager->isLoaded()) { - return false; - } - - return true; -} - -RenderData RenderStyle::getRenderData(MapDebugOptions debugOptions, float angle) { - RenderData result; - - for (const auto& entry : renderSources) { - if (entry.second->isEnabled()) { - result.sources.insert(entry.second.get()); - } - } - - for (auto& layerImpl : *layerImpls) { - RenderLayer* layer = getRenderLayer(layerImpl->id); - assert(layer); - - if (!layer->needsRendering(zoomHistory.lastZoom)) { - continue; - } - - if (const RenderBackgroundLayer* background = layer->as<RenderBackgroundLayer>()) { - if (debugOptions & MapDebugOptions::Overdraw) { - // We want to skip glClear optimization in overdraw mode. - result.order.emplace_back(*layer, nullptr); - continue; - } - const BackgroundPaintProperties::PossiblyEvaluated& paint = background->evaluated; - if (layerImpl.get() == layerImpls->at(0).get() && paint.get<BackgroundPattern>().from.empty()) { - // This is a solid background. We can use glClear(). - result.backgroundColor = paint.get<BackgroundColor>() * paint.get<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, nullptr); - } - continue; - } - - if (layer->is<RenderCustomLayer>()) { - result.order.emplace_back(*layer, nullptr); - continue; - } - - RenderSource* source = getRenderSource(layer->baseImpl->source); - if (!source) { - Log::Warning(Event::Render, "can't find source for layer '%s'", layer->getID().c_str()); - continue; - } - - const bool symbolLayer = layer->is<RenderSymbolLayer>(); - - auto sortedTiles = source->getRenderTiles(); - if (symbolLayer) { - // Sort symbol tiles in opposite y position, so tiles with overlapping symbols are drawn - // on top of each other, with lower symbols being drawn on top of higher symbols. - std::sort(sortedTiles.begin(), sortedTiles.end(), - [angle](const RenderTile& a, const RenderTile& b) { - Point<float> pa(a.id.canonical.x, a.id.canonical.y); - Point<float> pb(b.id.canonical.x, b.id.canonical.y); - - auto par = util::rotate(pa, angle); - auto pbr = util::rotate(pb, angle); - - return std::tie(par.y, par.x) < std::tie(pbr.y, pbr.x); - }); - } else { - std::sort(sortedTiles.begin(), sortedTiles.end(), - [](const auto& a, const auto& b) { return a.get().id < b.get().id; }); - } - - std::vector<std::reference_wrapper<RenderTile>> sortedTilesForInsertion; - for (auto& sortedTile : sortedTiles) { - auto& tile = sortedTile.get(); - if (!tile.tile.isRenderable()) { - continue; - } - - // We're not clipping symbol layers, so when we have both parents and children of symbol - // layers, we drop all children in favor of their parent to avoid duplicate labels. - // See https://github.com/mapbox/mapbox-gl-native/issues/2482 - if (symbolLayer) { - bool skip = false; - // Look back through the buckets we decided to render to find out whether there is - // 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 = sortedTilesForInsertion.rbegin(); - it != sortedTilesForInsertion.rend(); ++it) { - if (tile.tile.id.isChildOf(it->get().tile.id)) { - skip = true; - break; - } - } - if (skip) { - continue; - } - } - - auto bucket = tile.tile.getBucket(*layer->baseImpl); - if (bucket) { - sortedTilesForInsertion.emplace_back(tile); - tile.used = true; - } - } - layer->setRenderTiles(std::move(sortedTilesForInsertion)); - result.order.emplace_back(*layer, source); - } - - return result; -} - -std::vector<Feature> RenderStyle::queryRenderedFeatures(const ScreenLineString& geometry, - const TransformState& transformState, - const RenderedQueryOptions& options) const { - std::unordered_map<std::string, std::vector<Feature>> resultsByLayer; - - if (options.layerIDs) { - std::unordered_set<std::string> sourceIDs; - for (const auto& layerID : *options.layerIDs) { - if (const RenderLayer* layer = getRenderLayer(layerID)) { - sourceIDs.emplace(layer->baseImpl->source); - } - } - for (const auto& sourceID : sourceIDs) { - if (RenderSource* renderSource = getRenderSource(sourceID)) { - auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, *this, options); - std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin())); - } - } - } else { - for (const auto& entry : renderSources) { - auto sourceResults = entry.second->queryRenderedFeatures(geometry, transformState, *this, options); - 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& layerImpl : *layerImpls) { - const RenderLayer* layer = getRenderLayer(layerImpl->id); - if (!layer->needsRendering(zoomHistory.lastZoom)) { - continue; - } - auto it = resultsByLayer.find(layer->baseImpl->id); - if (it != resultsByLayer.end()) { - std::move(it->second.begin(), it->second.end(), std::back_inserter(result)); - } - } - - return result; -} - -void RenderStyle::onLowMemory() { - for (const auto& entry : renderSources) { - entry.second->onLowMemory(); - } -} - -void RenderStyle::onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) { - Log::Error(Event::Style, "Failed to load glyph range %d-%d for font stack %s: %s", - glyphRange.first, glyphRange.second, fontStackToString(fontStack).c_str(), util::toString(error).c_str()); - observer->onResourceError(error); -} - -void RenderStyle::onTileError(RenderSource& source, const OverscaledTileID& tileID, std::exception_ptr error) { - Log::Error(Event::Style, "Failed to load tile %s for source %s: %s", - util::toString(tileID).c_str(), source.baseImpl->id.c_str(), util::toString(error).c_str()); - observer->onResourceError(error); -} - -void RenderStyle::onTileChanged(RenderSource&, const OverscaledTileID&) { - observer->onInvalidate(); -} - -void RenderStyle::dumpDebugLogs() const { - for (const auto& entry : renderSources) { - entry.second->dumpDebugLogs(); - } - - imageManager->dumpDebugLogs(); -} - -} // namespace mbgl diff --git a/src/mbgl/renderer/render_style.hpp b/src/mbgl/renderer/render_style.hpp deleted file mode 100644 index 23a640c482..0000000000 --- a/src/mbgl/renderer/render_style.hpp +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -#include <mbgl/style/image.hpp> -#include <mbgl/renderer/render_source.hpp> -#include <mbgl/renderer/render_source_observer.hpp> -#include <mbgl/renderer/render_layer.hpp> -#include <mbgl/renderer/render_light.hpp> -#include <mbgl/text/glyph_manager_observer.hpp> -#include <mbgl/map/zoom_history.hpp> -#include <mbgl/map/mode.hpp> - -#include <memory> -#include <string> -#include <vector> - -namespace mbgl { - -class FileSource; -class GlyphManager; -class ImageManager; -class LineAtlas; -class RenderData; -class TransformState; -class RenderedQueryOptions; -class Scheduler; -class UpdateParameters; -class RenderStyleObserver; - -namespace style { -class Image; -class Source; -class Layer; -} // namespace style - -class RenderStyle : public GlyphManagerObserver, - public RenderSourceObserver { -public: - RenderStyle(Scheduler&, FileSource&); - ~RenderStyle() final; - - void setObserver(RenderStyleObserver*); - void update(const UpdateParameters&); - - bool isLoaded() const; - bool hasTransitions() const; - - RenderSource* getRenderSource(const std::string& id) const; - - std::vector<const RenderLayer*> getRenderLayers() const; - - RenderLayer* getRenderLayer(const std::string& id); - const RenderLayer* getRenderLayer(const std::string& id) const; - - const RenderLight& getRenderLight() const; - - RenderData getRenderData(MapDebugOptions, float angle); - - std::vector<Feature> queryRenderedFeatures(const ScreenLineString& geometry, - const TransformState& transformState, - const RenderedQueryOptions& options) const; - - void onLowMemory(); - - void dumpDebugLogs() const; - - Scheduler& scheduler; - FileSource& fileSource; - std::unique_ptr<GlyphManager> glyphManager; - std::unique_ptr<ImageManager> imageManager; - std::unique_ptr<LineAtlas> lineAtlas; - -private: - Immutable<std::vector<Immutable<style::Image::Impl>>> imageImpls; - Immutable<std::vector<Immutable<style::Source::Impl>>> sourceImpls; - Immutable<std::vector<Immutable<style::Layer::Impl>>> layerImpls; - - std::unordered_map<std::string, std::unique_ptr<RenderSource>> renderSources; - std::unordered_map<std::string, std::unique_ptr<RenderLayer>> renderLayers; - RenderLight renderLight; - - // GlyphManagerObserver implementation. - void onGlyphsError(const FontStack&, const GlyphRange&, std::exception_ptr) override; - - // RenderSourceObserver implementation. - void onTileChanged(RenderSource&, const OverscaledTileID&) override; - void onTileError(RenderSource&, const OverscaledTileID&, std::exception_ptr) override; - - RenderStyleObserver* observer; - ZoomHistory zoomHistory; -}; - -} // namespace mbgl diff --git a/src/mbgl/renderer/render_style_observer.hpp b/src/mbgl/renderer/render_style_observer.hpp deleted file mode 100644 index 5852dd68b8..0000000000 --- a/src/mbgl/renderer/render_style_observer.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include <exception> - -namespace mbgl { - -class RenderStyleObserver { -public: - virtual ~RenderStyleObserver() = default; - virtual void onInvalidate() {} - virtual void onResourceError(std::exception_ptr) {} -}; - -} // namespace mbgl diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index 6a8c18792e..d7886ebe88 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -298,7 +298,9 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { if (const RenderBackgroundLayer* background = layer->as<RenderBackgroundLayer>()) { const BackgroundPaintProperties::PossiblyEvaluated& paint = background->evaluated; - if (layerImpl.get() == layerImpls->at(0).get() && paint.get<BackgroundPattern>().from.empty()) { + if (parameters.contextMode == GLContextMode::Unique + && layerImpl.get() == layerImpls->at(0).get() + && paint.get<BackgroundPattern>().from.empty()) { // This is a solid background. We can use glClear(). backgroundColor = paint.get<BackgroundColor>() * paint.get<BackgroundOpacity>(); } else { @@ -434,13 +436,19 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { // Renders the backdrop of the OpenGL view. This also paints in areas where we don't have any // tiles whatsoever. { + using namespace gl::value; + MBGL_DEBUG_GROUP(parameters.context, "clear"); parameters.backend.bind(); - parameters.context.clear((parameters.debugOptions & MapDebugOptions::Overdraw) - ? Color::black() - : backgroundColor, - 1.0f, - 0); + if (parameters.debugOptions & MapDebugOptions::Overdraw) { + parameters.context.clear(Color::black(), ClearDepth::Default, ClearStencil::Default); + } else if (parameters.contextMode == GLContextMode::Shared) { + // Preserve the shared context background colors, clearing only alpha. + optional<gl::ColorMode::Mask> mask = { { false, false, false, true } }; + parameters.context.clear(backgroundColor, ClearDepth::Default, ClearStencil::Default, mask); + } else { + parameters.context.clear(backgroundColor, ClearDepth::Default, ClearStencil::Default); + } } // - CLIPPING MASKS ---------------------------------------------------------------------------- diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp index 30e7f70722..043253a834 100644 --- a/src/mbgl/renderer/renderer_impl.hpp +++ b/src/mbgl/renderer/renderer_impl.hpp @@ -1,5 +1,6 @@ #pragma once +#include <mbgl/renderer/mode.hpp> #include <mbgl/renderer/renderer.hpp> #include <mbgl/renderer/render_source_observer.hpp> #include <mbgl/renderer/render_light.hpp> @@ -9,7 +10,6 @@ #include <mbgl/style/layer.hpp> #include <mbgl/map/transform_state.hpp> #include <mbgl/map/zoom_history.hpp> -#include <mbgl/map/mode.hpp> #include <mbgl/text/glyph_manager_observer.hpp> #include <memory> diff --git a/src/mbgl/storage/file_source_request.cpp b/src/mbgl/storage/file_source_request.cpp deleted file mode 100644 index 09ea8cc32a..0000000000 --- a/src/mbgl/storage/file_source_request.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include <mbgl/storage/file_source_request.hpp> - -#include <mbgl/actor/mailbox.hpp> -#include <mbgl/actor/scheduler.hpp> - -namespace mbgl { - -FileSourceRequest::FileSourceRequest(FileSource::Callback&& callback) - : responseCallback(callback) - , mailbox(std::make_shared<Mailbox>(*Scheduler::GetCurrent())) { -} - -FileSourceRequest::~FileSourceRequest() { - if (cancelCallback) { - cancelCallback(); - } - - mailbox->close(); -} - -void FileSourceRequest::onCancel(std::function<void()>&& callback) { - cancelCallback = std::move(callback); -} - -void FileSourceRequest::setResponse(const Response& response) { - // Copy, because calling the callback will sometimes self - // destroy this object. We cannot move because this method - // can be called more than one. - auto callback = responseCallback; - callback(response); -} - -ActorRef<FileSourceRequest> FileSourceRequest::actor() { - return ActorRef<FileSourceRequest>(*this, mailbox); -} - -} // namespace mbgl diff --git a/src/mbgl/storage/file_source_request.hpp b/src/mbgl/storage/file_source_request.hpp deleted file mode 100644 index 6bd0d44df6..0000000000 --- a/src/mbgl/storage/file_source_request.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include <mbgl/actor/actor_ref.hpp> -#include <mbgl/storage/file_source.hpp> -#include <mbgl/util/async_request.hpp> - -#include <memory> -#include <functional> - -namespace mbgl { - -class Mailbox; - -class FileSourceRequest : public AsyncRequest { -public: - FileSourceRequest(FileSource::Callback&& callback); - ~FileSourceRequest() final; - - void onCancel(std::function<void()>&& callback); - void setResponse(const Response& res); - - ActorRef<FileSourceRequest> actor(); - -private: - FileSource::Callback responseCallback = nullptr; - std::function<void()> cancelCallback = nullptr; - - std::shared_ptr<Mailbox> mailbox; -}; - -} // namespace mbgl diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp new file mode 100644 index 0000000000..e837c4e70b --- /dev/null +++ b/src/mbgl/style/conversion/constant.cpp @@ -0,0 +1,94 @@ +#include <mbgl/style/conversion/constant.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<bool> Converter<bool>::operator()(const Convertible& value, Error& error) const { + optional<bool> converted = toBool(value); + if (!converted) { + error = { "value must be a boolean" }; + return {}; + } + return *converted; +} + +optional<float> Converter<float>::operator()(const Convertible& value, Error& error) const { + optional<float> converted = toNumber(value); + if (!converted) { + error = { "value must be a number" }; + return {}; + } + return *converted; +} + +optional<std::string> Converter<std::string>::operator()(const Convertible& value, Error& error) const { + optional<std::string> converted = toString(value); + if (!converted) { + error = { "value must be a string" }; + return {}; + } + return *converted; +} + +optional<Color> Converter<Color>::operator()(const Convertible& value, Error& error) const { + optional<std::string> string = toString(value); + if (!string) { + error = { "value must be a string" }; + return {}; + } + + optional<Color> color = Color::parse(*string); + if (!color) { + error = { "value must be a valid color" }; + return {}; + } + + return *color; +} + +optional<std::vector<float>> Converter<std::vector<float>>::operator()(const Convertible& value, Error& error) const { + if (!isArray(value)) { + error = { "value must be an array" }; + return {}; + } + + std::vector<float> result; + result.reserve(arrayLength(value)); + + for (std::size_t i = 0; i < arrayLength(value); ++i) { + optional<float> number = toNumber(arrayMember(value, i)); + if (!number) { + error = { "value must be an array of numbers" }; + return {}; + } + result.push_back(*number); + } + + return result; +} + +optional<std::vector<std::string>> Converter<std::vector<std::string>>::operator()(const Convertible& value, Error& error) const { + if (!isArray(value)) { + error = { "value must be an array" }; + return {}; + } + + std::vector<std::string> result; + result.reserve(arrayLength(value)); + + for (std::size_t i = 0; i < arrayLength(value); ++i) { + optional<std::string> string = toString(arrayMember(value, i)); + if (!string) { + error = { "value must be an array of strings" }; + return {}; + } + result.push_back(*string); + } + + return result; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/coordinate.cpp b/src/mbgl/style/conversion/coordinate.cpp new file mode 100644 index 0000000000..9b2be3381e --- /dev/null +++ b/src/mbgl/style/conversion/coordinate.cpp @@ -0,0 +1,29 @@ +#include <mbgl/style/conversion/coordinate.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<LatLng> Converter<LatLng>::operator() (const Convertible& value, Error& error) const { + if (!isArray(value) || arrayLength(value) < 2 ) { + error = { "coordinate array must contain numeric longitude and latitude values" }; + return {}; + } + //Style spec uses GeoJSON convention for specifying coordinates + optional<double> latitude = toDouble(arrayMember(value, 1)); + optional<double> longitude = toDouble(arrayMember(value, 0)); + + if (!latitude || !longitude) { + error = { "coordinate array must contain numeric longitude and latitude values" }; + return {}; + } + if (*latitude < -90 || *latitude > 90 ){ + error = { "coordinate latitude must be between -90 and 90" }; + return {}; + } + return LatLng(*latitude, *longitude); +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/filter.cpp b/src/mbgl/style/conversion/filter.cpp new file mode 100644 index 0000000000..bb7bb6ea98 --- /dev/null +++ b/src/mbgl/style/conversion/filter.cpp @@ -0,0 +1,248 @@ +#include <mbgl/style/conversion/filter.hpp> +#include <mbgl/util/geometry.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +static optional<Value> normalizeValue(const optional<Value>& value, Error& error) { + if (!value) { + error = { "filter expression value must be a boolean, number, or string" }; + return {}; + } else { + return *value; + } +} + +static optional<FeatureType> toFeatureType(const Convertible& value, Error& error) { + optional<std::string> type = toString(value); + if (!type) { + error = { "value for $type filter must be a string" }; + return {}; + } else if (*type == "Point") { + return FeatureType::Point; + } else if (*type == "LineString") { + return FeatureType::LineString; + } else if (*type == "Polygon") { + return FeatureType::Polygon; + } else { + error = { "value for $type filter must be Point, LineString, or Polygon" }; + return {}; + } +} + +static optional<FeatureIdentifier> toFeatureIdentifier(const Convertible& value, Error& error) { + optional<Value> identifier = toValue(value); + if (!identifier) { + error = { "filter expression value must be a boolean, number, or string" }; + return {}; + } else { + return (*identifier).match( + [] (uint64_t t) -> optional<FeatureIdentifier> { return { t }; }, + [] ( int64_t t) -> optional<FeatureIdentifier> { return { t }; }, + [] ( double t) -> optional<FeatureIdentifier> { return { t }; }, + [] (const std::string& t) -> optional<FeatureIdentifier> { return { t }; }, + [&] (const auto&) -> optional<FeatureIdentifier> { + error = { "filter expression value must be a boolean, number, or string" }; + return {}; + }); + } +} + +template <class FilterType, class IdentifierFilterType> +optional<Filter> convertUnaryFilter(const Convertible& value, Error& error) { + if (arrayLength(value) < 2) { + error = { "filter expression must have 2 elements" }; + return {}; + } + + optional<std::string> key = toString(arrayMember(value, 1)); + if (!key) { + error = { "filter expression key must be a string" }; + return {}; + } + + if (*key == "$id") { + return { IdentifierFilterType {} }; + } else { + return { FilterType { *key } }; + } +} + +template <class FilterType, class TypeFilterType, class IdentifierFilterType> +optional<Filter> convertEqualityFilter(const Convertible& value, Error& error) { + if (arrayLength(value) < 3) { + error = { "filter expression must have 3 elements" }; + return {}; + } + + optional<std::string> key = toString(arrayMember(value, 1)); + if (!key) { + error = { "filter expression key must be a string" }; + return {}; + } + + if (*key == "$type") { + optional<FeatureType> filterValue = toFeatureType(arrayMember(value, 2), error); + if (!filterValue) { + return {}; + } + + return { TypeFilterType { *filterValue } }; + + } else if (*key == "$id") { + optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, 2), error); + if (!filterValue) { + return {}; + } + + return { IdentifierFilterType { *filterValue } }; + + } else { + optional<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); + if (!filterValue) { + return {}; + } + + return { FilterType { *key, *filterValue } }; + } +} + +template <class FilterType> +optional<Filter> convertBinaryFilter(const Convertible& value, Error& error) { + if (arrayLength(value) < 3) { + error = { "filter expression must have 3 elements" }; + return {}; + } + + optional<std::string> key = toString(arrayMember(value, 1)); + if (!key) { + error = { "filter expression key must be a string" }; + return {}; + } + + optional<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); + if (!filterValue) { + return {}; + } + + return { FilterType { *key, *filterValue } }; +} + +template <class FilterType, class TypeFilterType, class IdentifierFilterType> +optional<Filter> convertSetFilter(const Convertible& value, Error& error) { + if (arrayLength(value) < 2) { + error = { "filter expression must at least 2 elements" }; + return {}; + } + + optional<std::string> key = toString(arrayMember(value, 1)); + if (!key) { + error = { "filter expression key must be a string" }; + return {}; + } + + if (*key == "$type") { + std::vector<FeatureType> values; + for (std::size_t i = 2; i < arrayLength(value); ++i) { + optional<FeatureType> filterValue = toFeatureType(arrayMember(value, i), error); + if (!filterValue) { + return {}; + } + values.push_back(*filterValue); + } + + return { TypeFilterType { std::move(values) } }; + + } else if (*key == "$id") { + std::vector<FeatureIdentifier> values; + for (std::size_t i = 2; i < arrayLength(value); ++i) { + optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, i), error); + if (!filterValue) { + return {}; + } + values.push_back(*filterValue); + } + + return { IdentifierFilterType { std::move(values) } }; + + } else { + std::vector<Value> values; + for (std::size_t i = 2; i < arrayLength(value); ++i) { + optional<Value> filterValue = normalizeValue(toValue(arrayMember(value, i)), error); + if (!filterValue) { + return {}; + } + values.push_back(*filterValue); + } + + return { FilterType { *key, std::move(values) } }; + } +} + +template <class FilterType> +optional<Filter> convertCompoundFilter(const Convertible& value, Error& error) { + std::vector<Filter> filters; + for (std::size_t i = 1; i < arrayLength(value); ++i) { + optional<Filter> element = convert<Filter>(arrayMember(value, i), error); + if (!element) { + return {}; + } + filters.push_back(*element); + } + + return { FilterType { std::move(filters) } }; +} + +optional<Filter> Converter<Filter>::operator()(const Convertible& value, Error& error) const { + if (!isArray(value)) { + error = { "filter expression must be an array" }; + return {}; + } + + if (arrayLength(value) < 1) { + error = { "filter expression must have at least 1 element" }; + return {}; + } + + optional<std::string> op = toString(arrayMember(value, 0)); + if (!op) { + error = { "filter operator must be a string" }; + return {}; + } + + if (*op == "==") { + return convertEqualityFilter<EqualsFilter, TypeEqualsFilter, IdentifierEqualsFilter>(value, error); + } else if (*op == "!=") { + return convertEqualityFilter<NotEqualsFilter, TypeNotEqualsFilter, IdentifierNotEqualsFilter>(value, error); + } else if (*op == ">") { + return convertBinaryFilter<GreaterThanFilter>(value, error); + } else if (*op == ">=") { + return convertBinaryFilter<GreaterThanEqualsFilter>(value, error); + } else if (*op == "<") { + return convertBinaryFilter<LessThanFilter>(value, error); + } else if (*op == "<=") { + return convertBinaryFilter<LessThanEqualsFilter>(value, error); + } else if (*op == "in") { + return convertSetFilter<InFilter, TypeInFilter, IdentifierInFilter>(value, error); + } else if (*op == "!in") { + return convertSetFilter<NotInFilter, TypeNotInFilter, IdentifierNotInFilter>(value, error); + } else if (*op == "all") { + return convertCompoundFilter<AllFilter>(value, error); + } else if (*op == "any") { + return convertCompoundFilter<AnyFilter>(value, error); + } else if (*op == "none") { + return convertCompoundFilter<NoneFilter>(value, error); + } else if (*op == "has") { + return convertUnaryFilter<HasFilter, HasIdentifierFilter>(value, error); + } else if (*op == "!has") { + return convertUnaryFilter<NotHasFilter, NotHasIdentifierFilter>(value, error); + } + + error = { R"(filter operator must be one of "==", "!=", ">", ">=", "<", "<=", "in", "!in", "all", "any", "none", "has", or "!has")" }; + return {}; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/geojson.cpp b/src/mbgl/style/conversion/geojson.cpp index 8103e9014a..e39a1a80eb 100644 --- a/src/mbgl/style/conversion/geojson.cpp +++ b/src/mbgl/style/conversion/geojson.cpp @@ -1,26 +1,16 @@ #include <mbgl/style/conversion/geojson.hpp> #include <mbgl/style/conversion/json.hpp> -#include <mbgl/util/rapidjson.hpp> - -#include <mapbox/geojson.hpp> -#include <mapbox/geojson/rapidjson.hpp> namespace mbgl { namespace style { namespace conversion { -optional<GeoJSON> Converter<GeoJSON>::operator()(const std::string& value, Error& error) const { - return convertJSON<GeoJSON>(value, error); +optional<GeoJSON> Converter<GeoJSON>::operator()(const Convertible& value, Error& error) const { + return toGeoJSON(value, error); } -template <> -optional<GeoJSON> Converter<GeoJSON>::operator()(const JSValue& value, Error& error) const { - try { - return mapbox::geojson::convert(value); - } catch (const std::exception& ex) { - error = { ex.what() }; - return {}; - } +optional<GeoJSON> parseGeoJSON(const std::string& value, Error& error) { + return convertJSON<GeoJSON>(value, error); } } // namespace conversion diff --git a/src/mbgl/style/conversion/geojson_options.cpp b/src/mbgl/style/conversion/geojson_options.cpp new file mode 100644 index 0000000000..a2c5ed8816 --- /dev/null +++ b/src/mbgl/style/conversion/geojson_options.cpp @@ -0,0 +1,85 @@ +#include <mbgl/style/conversion/geojson_options.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<GeoJSONOptions> Converter<GeoJSONOptions>::operator()(const Convertible& value, Error& error) const { + GeoJSONOptions options; + + const auto minzoomValue = objectMember(value, "minzoom"); + if (minzoomValue) { + if (toNumber(*minzoomValue)) { + options.minzoom = static_cast<uint8_t>(*toNumber(*minzoomValue)); + } else { + error = { "GeoJSON source minzoom value must be a number" }; + return {}; + } + } + + const auto maxzoomValue = objectMember(value, "maxzoom"); + if (maxzoomValue) { + if (toNumber(*maxzoomValue)) { + options.maxzoom = static_cast<uint8_t>(*toNumber(*maxzoomValue)); + } else { + error = { "GeoJSON source maxzoom value must be a number" }; + return {}; + } + } + + const auto bufferValue = objectMember(value, "buffer"); + if (bufferValue) { + if (toNumber(*bufferValue)) { + options.buffer = static_cast<uint16_t>(*toNumber(*bufferValue)); + } else { + error = { "GeoJSON source buffer value must be a number" }; + return {}; + } + } + + const auto toleranceValue = objectMember(value, "tolerance"); + if (toleranceValue) { + if (toNumber(*toleranceValue)) { + options.tolerance = static_cast<double>(*toNumber(*toleranceValue)); + } else { + error = { "GeoJSON source tolerance value must be a number" }; + return {}; + } + } + + const auto clusterValue = objectMember(value, "cluster"); + if (clusterValue) { + if (toBool(*clusterValue)) { + options.cluster = *toBool(*clusterValue); + } else { + error = { "GeoJSON source cluster value must be a boolean" }; + return {}; + } + } + + const auto clusterMaxZoomValue = objectMember(value, "clusterMaxZoom"); + if (clusterMaxZoomValue) { + if (toNumber(*clusterMaxZoomValue)) { + options.clusterMaxZoom = static_cast<uint8_t>(*toNumber(*clusterMaxZoomValue)); + } else { + error = { "GeoJSON source clusterMaxZoom value must be a number" }; + return {}; + } + } + + const auto clusterRadiusValue = objectMember(value, "clusterRadius"); + if (clusterRadiusValue) { + if (toNumber(*clusterRadiusValue)) { + options.clusterRadius = static_cast<double>(*toNumber(*clusterRadiusValue)); + } else { + error = { "GeoJSON source clusterRadius value must be a number" }; + return {}; + } + } + + return { options }; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/json.hpp b/src/mbgl/style/conversion/json.hpp index 0817ac09df..7dd2378f6b 100644 --- a/src/mbgl/style/conversion/json.hpp +++ b/src/mbgl/style/conversion/json.hpp @@ -20,7 +20,7 @@ optional<T> convertJSON(const std::string& json, Error& error, Args&&...args) { return {}; } - return convert<T, JSValue>(document, error, std::forward<Args>(args)...); + return convert<T>(document, error, std::forward<Args>(args)...); } } // namespace conversion diff --git a/src/mbgl/style/conversion/layer.cpp b/src/mbgl/style/conversion/layer.cpp new file mode 100644 index 0000000000..0ca582f8dc --- /dev/null +++ b/src/mbgl/style/conversion/layer.cpp @@ -0,0 +1,206 @@ +#include <mbgl/style/conversion/layer.hpp> +#include <mbgl/style/conversion/constant.hpp> +#include <mbgl/style/conversion/filter.hpp> +#include <mbgl/style/conversion/make_property_setters.hpp> +#include <mbgl/style/layers/background_layer.hpp> +#include <mbgl/style/layers/circle_layer.hpp> +#include <mbgl/style/layers/fill_layer.hpp> +#include <mbgl/style/layers/fill_extrusion_layer.hpp> +#include <mbgl/style/layers/line_layer.hpp> +#include <mbgl/style/layers/raster_layer.hpp> +#include <mbgl/style/layers/symbol_layer.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<Error> setLayoutProperty(Layer& layer, const std::string& name, const Convertible& value) { + static const auto setters = makeLayoutPropertySetters(); + auto it = setters.find(name); + if (it == setters.end()) { + return Error { "property not found" }; + } + return it->second(layer, value); +} + +optional<Error> setPaintProperty(Layer& layer, const std::string& name, const Convertible& value) { + static const auto setters = makePaintPropertySetters(); + auto it = setters.find(name); + if (it == setters.end()) { + return Error { "property not found" }; + } + return it->second(layer, value); +} + +optional<Error> setPaintProperties(Layer& layer, const Convertible& value) { + auto paintValue = objectMember(value, "paint"); + if (!paintValue) { + return {}; + } + return eachMember(*paintValue, [&] (const std::string& k, const Convertible& v) { + return setPaintProperty(layer, k, v); + }); +} + +template <class LayerType> +optional<std::unique_ptr<Layer>> convertVectorLayer(const std::string& id, const Convertible& value, Error& error) { + auto sourceValue = objectMember(value, "source"); + if (!sourceValue) { + error = { "layer must have a source" }; + return {}; + } + + optional<std::string> source = toString(*sourceValue); + if (!source) { + error = { "layer source must be a string" }; + return {}; + } + + std::unique_ptr<LayerType> layer = std::make_unique<LayerType>(id, *source); + + auto sourceLayerValue = objectMember(value, "source-layer"); + if (sourceLayerValue) { + optional<std::string> sourceLayer = toString(*sourceLayerValue); + if (!sourceLayer) { + error = { "layer source-layer must be a string" }; + return {}; + } + layer->setSourceLayer(*sourceLayer); + } + + auto filterValue = objectMember(value, "filter"); + if (filterValue) { + optional<Filter> filter = convert<Filter>(*filterValue, error); + if (!filter) { + return {}; + } + layer->setFilter(*filter); + } + + return { std::move(layer) }; +} + +static optional<std::unique_ptr<Layer>> convertRasterLayer(const std::string& id, const Convertible& value, Error& error) { + auto sourceValue = objectMember(value, "source"); + if (!sourceValue) { + error = { "layer must have a source" }; + return {}; + } + + optional<std::string> source = toString(*sourceValue); + if (!source) { + error = { "layer source must be a string" }; + return {}; + } + + return { std::make_unique<RasterLayer>(id, *source) }; +} + +static optional<std::unique_ptr<Layer>> convertBackgroundLayer(const std::string& id, const Convertible&, Error&) { + return { std::make_unique<BackgroundLayer>(id) }; +} + +optional<std::unique_ptr<Layer>> Converter<std::unique_ptr<Layer>>::operator()(const Convertible& value, Error& error) const { + if (!isObject(value)) { + error = { "layer must be an object" }; + return {}; + } + + auto idValue = objectMember(value, "id"); + if (!idValue) { + error = { "layer must have an id" }; + return {}; + } + + optional<std::string> id = toString(*idValue); + if (!id) { + error = { "layer id must be a string" }; + return {}; + } + + auto typeValue = objectMember(value, "type"); + if (!typeValue) { + error = { "layer must have a type" }; + return {}; + } + + optional<std::string> type = toString(*typeValue); + if (!type) { + error = { "layer type must be a string" }; + return {}; + } + + optional<std::unique_ptr<Layer>> converted; + + if (*type == "fill") { + converted = convertVectorLayer<FillLayer>(*id, value, error); + } else if (*type == "fill-extrusion") { + converted = convertVectorLayer<FillExtrusionLayer>(*id, value, error); + } else if (*type == "line") { + converted = convertVectorLayer<LineLayer>(*id, value, error); + } else if (*type == "circle") { + converted = convertVectorLayer<CircleLayer>(*id, value, error); + } else if (*type == "symbol") { + converted = convertVectorLayer<SymbolLayer>(*id, value, error); + } else if (*type == "raster") { + converted = convertRasterLayer(*id, value, error); + } else if (*type == "background") { + converted = convertBackgroundLayer(*id, value, error); + } else { + error = { "invalid layer type" }; + return {}; + } + + if (!converted) { + return converted; + } + + std::unique_ptr<Layer> layer = std::move(*converted); + + auto minzoomValue = objectMember(value, "minzoom"); + if (minzoomValue) { + optional<float> minzoom = toNumber(*minzoomValue); + if (!minzoom) { + error = { "minzoom must be numeric" }; + return {}; + } + layer->setMinZoom(*minzoom); + } + + auto maxzoomValue = objectMember(value, "maxzoom"); + if (maxzoomValue) { + optional<float> maxzoom = toNumber(*maxzoomValue); + if (!maxzoom) { + error = { "maxzoom must be numeric" }; + return {}; + } + layer->setMaxZoom(*maxzoom); + } + + auto layoutValue = objectMember(value, "layout"); + if (layoutValue) { + if (!isObject(*layoutValue)) { + error = { "layout must be an object" }; + return {}; + } + optional<Error> error_ = eachMember(*layoutValue, [&] (const std::string& k, const Convertible& v) { + return setLayoutProperty(*layer, k, v); + }); + if (error_) { + error = *error_; + return {}; + } + } + + optional<Error> error_ = setPaintProperties(*layer, value); + if (error_) { + error = *error_; + return {}; + } + + return std::move(layer); +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/light.cpp b/src/mbgl/style/conversion/light.cpp new file mode 100644 index 0000000000..f521f74386 --- /dev/null +++ b/src/mbgl/style/conversion/light.cpp @@ -0,0 +1,115 @@ +#include <mbgl/style/conversion/light.hpp> +#include <mbgl/style/conversion/position.hpp> +#include <mbgl/style/conversion/property_value.hpp> +#include <mbgl/style/conversion/transition_options.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<Light> Converter<Light>::operator()(const Convertible& value, Error& error) const { + if (!isObject(value)) { + error = { "light must be an object" }; + return {}; + } + + Light light; + + const auto anchor = objectMember(value, "anchor"); + if (anchor) { + optional<PropertyValue<LightAnchorType>> convertedAnchor = + convert<PropertyValue<LightAnchorType>>(*anchor, error); + + if (convertedAnchor) { + light.setAnchor(*convertedAnchor); + } else { + return {}; + } + } + + const auto anchorTransition = objectMember(value, "anchor-transition"); + if (anchorTransition) { + optional<TransitionOptions> transition = + convert<TransitionOptions>(*anchorTransition, error); + if (transition) { + light.setAnchorTransition(*transition); + } else { + return {}; + } + } + + const auto color = objectMember(value, "color"); + if (color) { + optional<PropertyValue<Color>> convertedColor = + convert<PropertyValue<Color>>(*color, error); + + if (convertedColor) { + light.setColor(*convertedColor); + } else { + return {}; + } + } + + const auto colorTransition = objectMember(value, "color-transition"); + if (colorTransition) { + optional<TransitionOptions> transition = + convert<TransitionOptions>(*colorTransition, error); + if (transition) { + light.setColorTransition(*transition); + } else { + return {}; + } + } + + const auto position = objectMember(value, "position"); + if (position) { + optional<PropertyValue<Position>> convertedPosition = + convert<PropertyValue<Position>>(*position, error); + + if (convertedPosition) { + light.setPosition(*convertedPosition); + } else { + return {}; + } + } + + const auto positionTransition = objectMember(value, "position-transition"); + if (positionTransition) { + optional<TransitionOptions> transition = + convert<TransitionOptions>(*positionTransition, error); + if (transition) { + light.setPositionTransition(*transition); + } else { + return {}; + } + } + + const auto intensity = objectMember(value, "intensity"); + if (intensity) { + optional<PropertyValue<float>> convertedIntensity = + convert<PropertyValue<float>>(*intensity, error); + + if (convertedIntensity) { + light.setIntensity(*convertedIntensity); + } else { + return {}; + } + } + + const auto intensityTransition = objectMember(value, "intensity-transition"); + if (intensityTransition) { + optional<TransitionOptions> transition = + convert<TransitionOptions>(*intensityTransition, error); + if (transition) { + light.setIntensityTransition(*transition); + } else { + return {}; + } + } + + return { std::move(light) }; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/make_property_setters.hpp b/src/mbgl/style/conversion/make_property_setters.hpp new file mode 100644 index 0000000000..074d7eb730 --- /dev/null +++ b/src/mbgl/style/conversion/make_property_setters.hpp @@ -0,0 +1,209 @@ +#pragma once + +// This file is generated. Edit make_property_setters.hpp.ejs, then run `make style-code`. + +#include <mbgl/style/conversion/property_setter.hpp> + +#include <mbgl/style/layers/fill_layer.hpp> +#include <mbgl/style/layers/line_layer.hpp> +#include <mbgl/style/layers/symbol_layer.hpp> +#include <mbgl/style/layers/circle_layer.hpp> +#include <mbgl/style/layers/fill_extrusion_layer.hpp> +#include <mbgl/style/layers/raster_layer.hpp> +#include <mbgl/style/layers/background_layer.hpp> + +#include <unordered_map> + +namespace mbgl { +namespace style { +namespace conversion { + +inline auto makeLayoutPropertySetters() { + std::unordered_map<std::string, PropertySetter> result; + + result["visibility"] = &setVisibility; + + + result["line-cap"] = &setProperty<LineLayer, PropertyValue<LineCapType>, &LineLayer::setLineCap>; + result["line-join"] = &setProperty<LineLayer, DataDrivenPropertyValue<LineJoinType>, &LineLayer::setLineJoin>; + result["line-miter-limit"] = &setProperty<LineLayer, PropertyValue<float>, &LineLayer::setLineMiterLimit>; + result["line-round-limit"] = &setProperty<LineLayer, PropertyValue<float>, &LineLayer::setLineRoundLimit>; + + result["symbol-placement"] = &setProperty<SymbolLayer, PropertyValue<SymbolPlacementType>, &SymbolLayer::setSymbolPlacement>; + result["symbol-spacing"] = &setProperty<SymbolLayer, PropertyValue<float>, &SymbolLayer::setSymbolSpacing>; + result["symbol-avoid-edges"] = &setProperty<SymbolLayer, PropertyValue<bool>, &SymbolLayer::setSymbolAvoidEdges>; + result["icon-allow-overlap"] = &setProperty<SymbolLayer, PropertyValue<bool>, &SymbolLayer::setIconAllowOverlap>; + result["icon-ignore-placement"] = &setProperty<SymbolLayer, PropertyValue<bool>, &SymbolLayer::setIconIgnorePlacement>; + result["icon-optional"] = &setProperty<SymbolLayer, PropertyValue<bool>, &SymbolLayer::setIconOptional>; + result["icon-rotation-alignment"] = &setProperty<SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setIconRotationAlignment>; + result["icon-size"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setIconSize>; + result["icon-text-fit"] = &setProperty<SymbolLayer, PropertyValue<IconTextFitType>, &SymbolLayer::setIconTextFit>; + result["icon-text-fit-padding"] = &setProperty<SymbolLayer, PropertyValue<std::array<float, 4>>, &SymbolLayer::setIconTextFitPadding>; + result["icon-image"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<std::string>, &SymbolLayer::setIconImage>; + result["icon-rotate"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setIconRotate>; + result["icon-padding"] = &setProperty<SymbolLayer, PropertyValue<float>, &SymbolLayer::setIconPadding>; + result["icon-keep-upright"] = &setProperty<SymbolLayer, PropertyValue<bool>, &SymbolLayer::setIconKeepUpright>; + result["icon-offset"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<std::array<float, 2>>, &SymbolLayer::setIconOffset>; + result["icon-anchor"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<SymbolAnchorType>, &SymbolLayer::setIconAnchor>; + result["icon-pitch-alignment"] = &setProperty<SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setIconPitchAlignment>; + result["text-pitch-alignment"] = &setProperty<SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setTextPitchAlignment>; + result["text-rotation-alignment"] = &setProperty<SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setTextRotationAlignment>; + result["text-field"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<std::string>, &SymbolLayer::setTextField>; + result["text-font"] = &setProperty<SymbolLayer, PropertyValue<std::vector<std::string>>, &SymbolLayer::setTextFont>; + result["text-size"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextSize>; + result["text-max-width"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextMaxWidth>; + result["text-line-height"] = &setProperty<SymbolLayer, PropertyValue<float>, &SymbolLayer::setTextLineHeight>; + result["text-letter-spacing"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextLetterSpacing>; + result["text-justify"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<TextJustifyType>, &SymbolLayer::setTextJustify>; + result["text-anchor"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<SymbolAnchorType>, &SymbolLayer::setTextAnchor>; + result["text-max-angle"] = &setProperty<SymbolLayer, PropertyValue<float>, &SymbolLayer::setTextMaxAngle>; + result["text-rotate"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextRotate>; + result["text-padding"] = &setProperty<SymbolLayer, PropertyValue<float>, &SymbolLayer::setTextPadding>; + result["text-keep-upright"] = &setProperty<SymbolLayer, PropertyValue<bool>, &SymbolLayer::setTextKeepUpright>; + result["text-transform"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<TextTransformType>, &SymbolLayer::setTextTransform>; + result["text-offset"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<std::array<float, 2>>, &SymbolLayer::setTextOffset>; + result["text-allow-overlap"] = &setProperty<SymbolLayer, PropertyValue<bool>, &SymbolLayer::setTextAllowOverlap>; + result["text-ignore-placement"] = &setProperty<SymbolLayer, PropertyValue<bool>, &SymbolLayer::setTextIgnorePlacement>; + result["text-optional"] = &setProperty<SymbolLayer, PropertyValue<bool>, &SymbolLayer::setTextOptional>; + + + + + + return result; +} + +inline auto makePaintPropertySetters() { + std::unordered_map<std::string, PropertySetter> result; + + result["fill-antialias"] = &setProperty<FillLayer, PropertyValue<bool>, &FillLayer::setFillAntialias>; + result["fill-antialias-transition"] = &setTransition<FillLayer, &FillLayer::setFillAntialiasTransition>; + result["fill-opacity"] = &setProperty<FillLayer, DataDrivenPropertyValue<float>, &FillLayer::setFillOpacity>; + result["fill-opacity-transition"] = &setTransition<FillLayer, &FillLayer::setFillOpacityTransition>; + result["fill-color"] = &setProperty<FillLayer, DataDrivenPropertyValue<Color>, &FillLayer::setFillColor>; + result["fill-color-transition"] = &setTransition<FillLayer, &FillLayer::setFillColorTransition>; + result["fill-outline-color"] = &setProperty<FillLayer, DataDrivenPropertyValue<Color>, &FillLayer::setFillOutlineColor>; + result["fill-outline-color-transition"] = &setTransition<FillLayer, &FillLayer::setFillOutlineColorTransition>; + result["fill-translate"] = &setProperty<FillLayer, PropertyValue<std::array<float, 2>>, &FillLayer::setFillTranslate>; + result["fill-translate-transition"] = &setTransition<FillLayer, &FillLayer::setFillTranslateTransition>; + result["fill-translate-anchor"] = &setProperty<FillLayer, PropertyValue<TranslateAnchorType>, &FillLayer::setFillTranslateAnchor>; + result["fill-translate-anchor-transition"] = &setTransition<FillLayer, &FillLayer::setFillTranslateAnchorTransition>; + result["fill-pattern"] = &setProperty<FillLayer, PropertyValue<std::string>, &FillLayer::setFillPattern>; + result["fill-pattern-transition"] = &setTransition<FillLayer, &FillLayer::setFillPatternTransition>; + + result["line-opacity"] = &setProperty<LineLayer, DataDrivenPropertyValue<float>, &LineLayer::setLineOpacity>; + result["line-opacity-transition"] = &setTransition<LineLayer, &LineLayer::setLineOpacityTransition>; + result["line-color"] = &setProperty<LineLayer, DataDrivenPropertyValue<Color>, &LineLayer::setLineColor>; + result["line-color-transition"] = &setTransition<LineLayer, &LineLayer::setLineColorTransition>; + result["line-translate"] = &setProperty<LineLayer, PropertyValue<std::array<float, 2>>, &LineLayer::setLineTranslate>; + result["line-translate-transition"] = &setTransition<LineLayer, &LineLayer::setLineTranslateTransition>; + result["line-translate-anchor"] = &setProperty<LineLayer, PropertyValue<TranslateAnchorType>, &LineLayer::setLineTranslateAnchor>; + result["line-translate-anchor-transition"] = &setTransition<LineLayer, &LineLayer::setLineTranslateAnchorTransition>; + result["line-width"] = &setProperty<LineLayer, DataDrivenPropertyValue<float>, &LineLayer::setLineWidth>; + result["line-width-transition"] = &setTransition<LineLayer, &LineLayer::setLineWidthTransition>; + result["line-gap-width"] = &setProperty<LineLayer, DataDrivenPropertyValue<float>, &LineLayer::setLineGapWidth>; + result["line-gap-width-transition"] = &setTransition<LineLayer, &LineLayer::setLineGapWidthTransition>; + result["line-offset"] = &setProperty<LineLayer, DataDrivenPropertyValue<float>, &LineLayer::setLineOffset>; + result["line-offset-transition"] = &setTransition<LineLayer, &LineLayer::setLineOffsetTransition>; + result["line-blur"] = &setProperty<LineLayer, DataDrivenPropertyValue<float>, &LineLayer::setLineBlur>; + result["line-blur-transition"] = &setTransition<LineLayer, &LineLayer::setLineBlurTransition>; + result["line-dasharray"] = &setProperty<LineLayer, PropertyValue<std::vector<float>>, &LineLayer::setLineDasharray>; + result["line-dasharray-transition"] = &setTransition<LineLayer, &LineLayer::setLineDasharrayTransition>; + result["line-pattern"] = &setProperty<LineLayer, PropertyValue<std::string>, &LineLayer::setLinePattern>; + result["line-pattern-transition"] = &setTransition<LineLayer, &LineLayer::setLinePatternTransition>; + + result["icon-opacity"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setIconOpacity>; + result["icon-opacity-transition"] = &setTransition<SymbolLayer, &SymbolLayer::setIconOpacityTransition>; + result["icon-color"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<Color>, &SymbolLayer::setIconColor>; + result["icon-color-transition"] = &setTransition<SymbolLayer, &SymbolLayer::setIconColorTransition>; + result["icon-halo-color"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<Color>, &SymbolLayer::setIconHaloColor>; + result["icon-halo-color-transition"] = &setTransition<SymbolLayer, &SymbolLayer::setIconHaloColorTransition>; + result["icon-halo-width"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setIconHaloWidth>; + result["icon-halo-width-transition"] = &setTransition<SymbolLayer, &SymbolLayer::setIconHaloWidthTransition>; + result["icon-halo-blur"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setIconHaloBlur>; + result["icon-halo-blur-transition"] = &setTransition<SymbolLayer, &SymbolLayer::setIconHaloBlurTransition>; + result["icon-translate"] = &setProperty<SymbolLayer, PropertyValue<std::array<float, 2>>, &SymbolLayer::setIconTranslate>; + result["icon-translate-transition"] = &setTransition<SymbolLayer, &SymbolLayer::setIconTranslateTransition>; + result["icon-translate-anchor"] = &setProperty<SymbolLayer, PropertyValue<TranslateAnchorType>, &SymbolLayer::setIconTranslateAnchor>; + result["icon-translate-anchor-transition"] = &setTransition<SymbolLayer, &SymbolLayer::setIconTranslateAnchorTransition>; + result["text-opacity"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextOpacity>; + result["text-opacity-transition"] = &setTransition<SymbolLayer, &SymbolLayer::setTextOpacityTransition>; + result["text-color"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<Color>, &SymbolLayer::setTextColor>; + result["text-color-transition"] = &setTransition<SymbolLayer, &SymbolLayer::setTextColorTransition>; + result["text-halo-color"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<Color>, &SymbolLayer::setTextHaloColor>; + result["text-halo-color-transition"] = &setTransition<SymbolLayer, &SymbolLayer::setTextHaloColorTransition>; + result["text-halo-width"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextHaloWidth>; + result["text-halo-width-transition"] = &setTransition<SymbolLayer, &SymbolLayer::setTextHaloWidthTransition>; + result["text-halo-blur"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextHaloBlur>; + result["text-halo-blur-transition"] = &setTransition<SymbolLayer, &SymbolLayer::setTextHaloBlurTransition>; + result["text-translate"] = &setProperty<SymbolLayer, PropertyValue<std::array<float, 2>>, &SymbolLayer::setTextTranslate>; + result["text-translate-transition"] = &setTransition<SymbolLayer, &SymbolLayer::setTextTranslateTransition>; + result["text-translate-anchor"] = &setProperty<SymbolLayer, PropertyValue<TranslateAnchorType>, &SymbolLayer::setTextTranslateAnchor>; + result["text-translate-anchor-transition"] = &setTransition<SymbolLayer, &SymbolLayer::setTextTranslateAnchorTransition>; + + result["circle-radius"] = &setProperty<CircleLayer, DataDrivenPropertyValue<float>, &CircleLayer::setCircleRadius>; + result["circle-radius-transition"] = &setTransition<CircleLayer, &CircleLayer::setCircleRadiusTransition>; + result["circle-color"] = &setProperty<CircleLayer, DataDrivenPropertyValue<Color>, &CircleLayer::setCircleColor>; + result["circle-color-transition"] = &setTransition<CircleLayer, &CircleLayer::setCircleColorTransition>; + result["circle-blur"] = &setProperty<CircleLayer, DataDrivenPropertyValue<float>, &CircleLayer::setCircleBlur>; + result["circle-blur-transition"] = &setTransition<CircleLayer, &CircleLayer::setCircleBlurTransition>; + result["circle-opacity"] = &setProperty<CircleLayer, DataDrivenPropertyValue<float>, &CircleLayer::setCircleOpacity>; + result["circle-opacity-transition"] = &setTransition<CircleLayer, &CircleLayer::setCircleOpacityTransition>; + result["circle-translate"] = &setProperty<CircleLayer, PropertyValue<std::array<float, 2>>, &CircleLayer::setCircleTranslate>; + result["circle-translate-transition"] = &setTransition<CircleLayer, &CircleLayer::setCircleTranslateTransition>; + result["circle-translate-anchor"] = &setProperty<CircleLayer, PropertyValue<TranslateAnchorType>, &CircleLayer::setCircleTranslateAnchor>; + result["circle-translate-anchor-transition"] = &setTransition<CircleLayer, &CircleLayer::setCircleTranslateAnchorTransition>; + result["circle-pitch-scale"] = &setProperty<CircleLayer, PropertyValue<CirclePitchScaleType>, &CircleLayer::setCirclePitchScale>; + result["circle-pitch-scale-transition"] = &setTransition<CircleLayer, &CircleLayer::setCirclePitchScaleTransition>; + result["circle-pitch-alignment"] = &setProperty<CircleLayer, PropertyValue<AlignmentType>, &CircleLayer::setCirclePitchAlignment>; + result["circle-pitch-alignment-transition"] = &setTransition<CircleLayer, &CircleLayer::setCirclePitchAlignmentTransition>; + result["circle-stroke-width"] = &setProperty<CircleLayer, DataDrivenPropertyValue<float>, &CircleLayer::setCircleStrokeWidth>; + result["circle-stroke-width-transition"] = &setTransition<CircleLayer, &CircleLayer::setCircleStrokeWidthTransition>; + result["circle-stroke-color"] = &setProperty<CircleLayer, DataDrivenPropertyValue<Color>, &CircleLayer::setCircleStrokeColor>; + result["circle-stroke-color-transition"] = &setTransition<CircleLayer, &CircleLayer::setCircleStrokeColorTransition>; + result["circle-stroke-opacity"] = &setProperty<CircleLayer, DataDrivenPropertyValue<float>, &CircleLayer::setCircleStrokeOpacity>; + result["circle-stroke-opacity-transition"] = &setTransition<CircleLayer, &CircleLayer::setCircleStrokeOpacityTransition>; + + result["fill-extrusion-opacity"] = &setProperty<FillExtrusionLayer, PropertyValue<float>, &FillExtrusionLayer::setFillExtrusionOpacity>; + result["fill-extrusion-opacity-transition"] = &setTransition<FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionOpacityTransition>; + result["fill-extrusion-color"] = &setProperty<FillExtrusionLayer, DataDrivenPropertyValue<Color>, &FillExtrusionLayer::setFillExtrusionColor>; + result["fill-extrusion-color-transition"] = &setTransition<FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionColorTransition>; + result["fill-extrusion-translate"] = &setProperty<FillExtrusionLayer, PropertyValue<std::array<float, 2>>, &FillExtrusionLayer::setFillExtrusionTranslate>; + result["fill-extrusion-translate-transition"] = &setTransition<FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionTranslateTransition>; + result["fill-extrusion-translate-anchor"] = &setProperty<FillExtrusionLayer, PropertyValue<TranslateAnchorType>, &FillExtrusionLayer::setFillExtrusionTranslateAnchor>; + result["fill-extrusion-translate-anchor-transition"] = &setTransition<FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionTranslateAnchorTransition>; + result["fill-extrusion-pattern"] = &setProperty<FillExtrusionLayer, PropertyValue<std::string>, &FillExtrusionLayer::setFillExtrusionPattern>; + result["fill-extrusion-pattern-transition"] = &setTransition<FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionPatternTransition>; + result["fill-extrusion-height"] = &setProperty<FillExtrusionLayer, DataDrivenPropertyValue<float>, &FillExtrusionLayer::setFillExtrusionHeight>; + result["fill-extrusion-height-transition"] = &setTransition<FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionHeightTransition>; + result["fill-extrusion-base"] = &setProperty<FillExtrusionLayer, DataDrivenPropertyValue<float>, &FillExtrusionLayer::setFillExtrusionBase>; + result["fill-extrusion-base-transition"] = &setTransition<FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionBaseTransition>; + + result["raster-opacity"] = &setProperty<RasterLayer, PropertyValue<float>, &RasterLayer::setRasterOpacity>; + result["raster-opacity-transition"] = &setTransition<RasterLayer, &RasterLayer::setRasterOpacityTransition>; + result["raster-hue-rotate"] = &setProperty<RasterLayer, PropertyValue<float>, &RasterLayer::setRasterHueRotate>; + result["raster-hue-rotate-transition"] = &setTransition<RasterLayer, &RasterLayer::setRasterHueRotateTransition>; + result["raster-brightness-min"] = &setProperty<RasterLayer, PropertyValue<float>, &RasterLayer::setRasterBrightnessMin>; + result["raster-brightness-min-transition"] = &setTransition<RasterLayer, &RasterLayer::setRasterBrightnessMinTransition>; + result["raster-brightness-max"] = &setProperty<RasterLayer, PropertyValue<float>, &RasterLayer::setRasterBrightnessMax>; + result["raster-brightness-max-transition"] = &setTransition<RasterLayer, &RasterLayer::setRasterBrightnessMaxTransition>; + result["raster-saturation"] = &setProperty<RasterLayer, PropertyValue<float>, &RasterLayer::setRasterSaturation>; + result["raster-saturation-transition"] = &setTransition<RasterLayer, &RasterLayer::setRasterSaturationTransition>; + result["raster-contrast"] = &setProperty<RasterLayer, PropertyValue<float>, &RasterLayer::setRasterContrast>; + result["raster-contrast-transition"] = &setTransition<RasterLayer, &RasterLayer::setRasterContrastTransition>; + result["raster-fade-duration"] = &setProperty<RasterLayer, PropertyValue<float>, &RasterLayer::setRasterFadeDuration>; + result["raster-fade-duration-transition"] = &setTransition<RasterLayer, &RasterLayer::setRasterFadeDurationTransition>; + + result["background-color"] = &setProperty<BackgroundLayer, PropertyValue<Color>, &BackgroundLayer::setBackgroundColor>; + result["background-color-transition"] = &setTransition<BackgroundLayer, &BackgroundLayer::setBackgroundColorTransition>; + result["background-pattern"] = &setProperty<BackgroundLayer, PropertyValue<std::string>, &BackgroundLayer::setBackgroundPattern>; + result["background-pattern-transition"] = &setTransition<BackgroundLayer, &BackgroundLayer::setBackgroundPatternTransition>; + result["background-opacity"] = &setProperty<BackgroundLayer, PropertyValue<float>, &BackgroundLayer::setBackgroundOpacity>; + result["background-opacity-transition"] = &setTransition<BackgroundLayer, &BackgroundLayer::setBackgroundOpacityTransition>; + + return result; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/position.cpp b/src/mbgl/style/conversion/position.cpp new file mode 100644 index 0000000000..702d250dbf --- /dev/null +++ b/src/mbgl/style/conversion/position.cpp @@ -0,0 +1,22 @@ +#include <mbgl/style/conversion/position.hpp> +#include <mbgl/style/conversion/constant.hpp> + +#include <array> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<Position> Converter<Position>::operator()(const Convertible& value, Error& error) const { + optional<std::array<float, 3>> spherical = convert<std::array<float, 3>>(value, error); + + if (!spherical) { + return {}; + } + + return Position(*spherical); +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/property_setter.hpp b/src/mbgl/style/conversion/property_setter.hpp new file mode 100644 index 0000000000..9e382b9c38 --- /dev/null +++ b/src/mbgl/style/conversion/property_setter.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include <mbgl/style/layer.hpp> +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/constant.hpp> +#include <mbgl/style/conversion/property_value.hpp> +#include <mbgl/style/conversion/data_driven_property_value.hpp> +#include <mbgl/style/conversion/transition_options.hpp> + +#include <string> + +namespace mbgl { +namespace style { +namespace conversion { + +using PropertySetter = optional<Error> (*) (Layer&, const Convertible&); + +template <class L, class PropertyValue, void (L::*setter)(PropertyValue)> +optional<Error> setProperty(Layer& layer, const Convertible& value) { + auto* typedLayer = layer.as<L>(); + if (!typedLayer) { + return Error { "layer doesn't support this property" }; + } + + Error error; + optional<PropertyValue> typedValue = convert<PropertyValue>(value, error); + if (!typedValue) { + return error; + } + + (typedLayer->*setter)(*typedValue); + return {}; +} + +template <class L, void (L::*setter)(const TransitionOptions&)> +optional<Error> setTransition(Layer& layer, const Convertible& value) { + auto* typedLayer = layer.as<L>(); + if (!typedLayer) { + return Error { "layer doesn't support this property" }; + } + + Error error; + optional<TransitionOptions> transition = convert<TransitionOptions>(value, error); + if (!transition) { + return error; + } + + (typedLayer->*setter)(*transition); + return {}; +} + +inline optional<Error> setVisibility(Layer& layer, const Convertible& value) { + if (isUndefined(value)) { + layer.setVisibility(VisibilityType::Visible); + return {}; + } + + Error error; + optional<VisibilityType> visibility = convert<VisibilityType>(value, error); + if (!visibility) { + return error; + } + + layer.setVisibility(*visibility); + return {}; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/source.cpp b/src/mbgl/style/conversion/source.cpp new file mode 100644 index 0000000000..c10d0babcf --- /dev/null +++ b/src/mbgl/style/conversion/source.cpp @@ -0,0 +1,175 @@ +#include <mbgl/style/conversion/source.hpp> +#include <mbgl/style/conversion/coordinate.hpp> +#include <mbgl/style/conversion/geojson.hpp> +#include <mbgl/style/conversion/geojson_options.hpp> +#include <mbgl/style/conversion/tileset.hpp> +#include <mbgl/style/sources/geojson_source.hpp> +#include <mbgl/style/sources/raster_source.hpp> +#include <mbgl/style/sources/vector_source.hpp> +#include <mbgl/style/sources/image_source.hpp> +#include <mbgl/util/geo.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +// A tile source can either specify a URL to TileJSON, or inline TileJSON. +static optional<variant<std::string, Tileset>> convertURLOrTileset(const Convertible& value, Error& error) { + auto urlVal = objectMember(value, "url"); + if (!urlVal) { + optional<Tileset> tileset = convert<Tileset>(value, error); + if (!tileset) { + return {}; + } + return { *tileset }; + } + + optional<std::string> url = toString(*urlVal); + if (!url) { + error = { "source url must be a string" }; + return {}; + } + + return { *url }; +} + +static optional<std::unique_ptr<Source>> convertRasterSource(const std::string& id, + const Convertible& value, + Error& error) { + optional<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value, error); + if (!urlOrTileset) { + return {}; + } + + uint16_t tileSize = util::tileSize; + auto tileSizeValue = objectMember(value, "tileSize"); + if (tileSizeValue) { + optional<float> size = toNumber(*tileSizeValue); + if (!size || *size < 0 || *size > std::numeric_limits<uint16_t>::max()) { + error = { "invalid tileSize" }; + return {}; + } + tileSize = *size; + } + + return { std::make_unique<RasterSource>(id, std::move(*urlOrTileset), tileSize) }; +} + +static optional<std::unique_ptr<Source>> convertVectorSource(const std::string& id, + const Convertible& value, + Error& error) { + optional<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value, error); + if (!urlOrTileset) { + return {}; + } + + return { std::make_unique<VectorSource>(id, std::move(*urlOrTileset)) }; +} + +static optional<std::unique_ptr<Source>> convertGeoJSONSource(const std::string& id, + const Convertible& value, + Error& error) { + auto dataValue = objectMember(value, "data"); + if (!dataValue) { + error = { "GeoJSON source must have a data value" }; + return {}; + } + + optional<GeoJSONOptions> options = convert<GeoJSONOptions>(value, error); + if (!options) { + return {}; + } + + auto result = std::make_unique<GeoJSONSource>(id, *options); + + if (isObject(*dataValue)) { + optional<GeoJSON> geoJSON = convert<GeoJSON>(*dataValue, error); + if (!geoJSON) { + return {}; + } + result->setGeoJSON(std::move(*geoJSON)); + } else if (toString(*dataValue)) { + result->setURL(*toString(*dataValue)); + } else { + error = { "GeoJSON data must be a URL or an object" }; + return {}; + } + + return { std::move(result) }; +} + +static optional<std::unique_ptr<Source>> convertImageSource(const std::string& id, + const Convertible& value, + Error& error) { + auto urlValue = objectMember(value, "url"); + if (!urlValue) { + error = { "Image source must have a url value" }; + return {}; + } + + auto urlString = toString(*urlValue); + if (!urlString) { + error = { "Image url must be a URL string" }; + return {}; + } + + auto coordinatesValue = objectMember(value, "coordinates"); + if (!coordinatesValue) { + error = { "Image source must have a coordinates values" }; + return {}; + } + + if (!isArray(*coordinatesValue) || arrayLength(*coordinatesValue) != 4) { + error = { "Image coordinates must be an array of four longitude latitude pairs" }; + return {}; + } + + std::array<LatLng, 4> coordinates; + for (std::size_t i=0; i < 4; i++) { + auto latLng = conversion::convert<LatLng>(arrayMember(*coordinatesValue,i), error); + if (!latLng) { + return {}; + } + coordinates[i] = *latLng; + } + auto result = std::make_unique<ImageSource>(id, coordinates); + result->setURL(*urlString); + + return { std::move(result) }; +} + +optional<std::unique_ptr<Source>> Converter<std::unique_ptr<Source>>::operator()(const Convertible& value, Error& error, const std::string& id) const { + if (!isObject(value)) { + error = { "source must be an object" }; + return {}; + } + + auto typeValue = objectMember(value, "type"); + if (!typeValue) { + error = { "source must have a type" }; + return {}; + } + + optional<std::string> type = toString(*typeValue); + if (!type) { + error = { "source type must be a string" }; + return {}; + } + + if (*type == "raster") { + return convertRasterSource(id, value, error); + } else if (*type == "vector") { + return convertVectorSource(id, value, error); + } else if (*type == "geojson") { + return convertGeoJSONSource(id, value, error); + } else if (*type == "image") { + return convertImageSource(id, value, error); + } else { + error = { "invalid source type" }; + return {}; + } +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/tileset.cpp b/src/mbgl/style/conversion/tileset.cpp new file mode 100644 index 0000000000..b9383c41b8 --- /dev/null +++ b/src/mbgl/style/conversion/tileset.cpp @@ -0,0 +1,73 @@ +#include <mbgl/style/conversion/tileset.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<Tileset> Converter<Tileset>::operator()(const Convertible& value, Error& error) const { + Tileset result; + + auto tiles = objectMember(value, "tiles"); + if (!tiles) { + error = { "source must have tiles" }; + return {}; + } + + if (!isArray(*tiles)) { + error = { "source tiles must be an array" }; + return {}; + } + + for (std::size_t i = 0; i < arrayLength(*tiles); i++) { + optional<std::string> urlTemplate = toString(arrayMember(*tiles, i)); + if (!urlTemplate) { + error = { "source tiles member must be a string" }; + return {}; + } + result.tiles.push_back(std::move(*urlTemplate)); + } + + auto schemeValue = objectMember(value, "scheme"); + if (schemeValue) { + optional<std::string> scheme = toString(*schemeValue); + if (scheme && *scheme == "tms") { + result.scheme = Tileset::Scheme::TMS; + } + } + + auto minzoomValue = objectMember(value, "minzoom"); + if (minzoomValue) { + optional<float> minzoom = toNumber(*minzoomValue); + if (!minzoom || *minzoom < 0 || *minzoom > std::numeric_limits<uint8_t>::max()) { + error = { "invalid minzoom" }; + return {}; + } + result.zoomRange.min = *minzoom; + } + + auto maxzoomValue = objectMember(value, "maxzoom"); + if (maxzoomValue) { + optional<float> maxzoom = toNumber(*maxzoomValue); + if (!maxzoom || *maxzoom < 0 || *maxzoom > std::numeric_limits<uint8_t>::max()) { + error = { "invalid maxzoom" }; + return {}; + } + result.zoomRange.max = *maxzoom; + } + + auto attributionValue = objectMember(value, "attribution"); + if (attributionValue) { + optional<std::string> attribution = toString(*attributionValue); + if (!attribution) { + error = { "source attribution must be a string" }; + return {}; + } + result.attribution = std::move(*attribution); + } + + return result; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/transition_options.cpp b/src/mbgl/style/conversion/transition_options.cpp new file mode 100644 index 0000000000..8a60c5bfd8 --- /dev/null +++ b/src/mbgl/style/conversion/transition_options.cpp @@ -0,0 +1,40 @@ +#include <mbgl/style/conversion/transition_options.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<TransitionOptions> Converter<TransitionOptions>::operator()(const Convertible& value, Error& error) const { + if (!isObject(value)) { + error = { "transition must be an object" }; + return {}; + } + + TransitionOptions result; + + auto duration = objectMember(value, "duration"); + if (duration) { + auto number = toNumber(*duration); + if (!number) { + error = { "duration must be a number" }; + return {}; + } + result.duration = { std::chrono::milliseconds(int64_t(*number)) }; + } + + auto delay = objectMember(value, "delay"); + if (delay) { + auto number = toNumber(*delay); + if (!number) { + error = { "delay must be a number" }; + return {}; + } + result.delay = { std::chrono::milliseconds(int64_t(*number)) }; + } + + return result; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp index a83897dbf5..10fce33986 100644 --- a/src/mbgl/style/parser.cpp +++ b/src/mbgl/style/parser.cpp @@ -1,11 +1,13 @@ #include <mbgl/style/parser.hpp> #include <mbgl/style/layer_impl.hpp> +#include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/rapidjson_conversion.hpp> #include <mbgl/style/conversion.hpp> #include <mbgl/style/conversion/coordinate.hpp> #include <mbgl/style/conversion/source.hpp> #include <mbgl/style/conversion/layer.hpp> #include <mbgl/style/conversion/light.hpp> +#include <mbgl/style/conversion/transition_options.hpp> #include <mbgl/util/logging.hpp> #include <mbgl/util/string.hpp> @@ -149,7 +151,7 @@ void Parser::parseSources(const JSValue& value) { } for (const auto& property : value.GetObject()) { - std::string id = *conversion::toString(property.name); + std::string id { property.name.GetString(), property.name.GetStringLength() }; conversion::Error error; optional<std::unique_ptr<Source>> source = @@ -256,7 +258,7 @@ void Parser::parseLayer(const std::string& id, const JSValue& value, std::unique } layer = reference->cloneRef(id); - conversion::setPaintProperties(*layer, value); + conversion::setPaintProperties(*layer, conversion::Convertible(&value)); } else { conversion::Error error; optional<std::unique_ptr<Layer>> converted = conversion::convert<std::unique_ptr<Layer>>(value, error); diff --git a/src/mbgl/style/rapidjson_conversion.hpp b/src/mbgl/style/rapidjson_conversion.hpp index 48a764ccb4..79bd9c928b 100644 --- a/src/mbgl/style/rapidjson_conversion.hpp +++ b/src/mbgl/style/rapidjson_conversion.hpp @@ -1,103 +1,125 @@ #pragma once #include <mbgl/util/rapidjson.hpp> -#include <mbgl/util/feature.hpp> #include <mbgl/style/conversion.hpp> +#include <mapbox/geojson.hpp> +#include <mapbox/geojson/rapidjson.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(); -} +template <> +class ConversionTraits<const JSValue*> { +public: + static bool isUndefined(const JSValue* value) { + return value->IsNull(); + } -inline std::size_t arrayLength(const JSValue& value) { - return value.Size(); -} + static bool isArray(const JSValue* value) { + return value->IsArray(); + } -inline const JSValue& arrayMember(const JSValue& value, std::size_t i) { - return value[rapidjson::SizeType(i)]; -} + static std::size_t arrayLength(const JSValue* value) { + return value->Size(); + } -inline bool isObject(const JSValue& value) { - return value.IsObject(); -} + static const JSValue* arrayMember(const JSValue* value, std::size_t i) { + return &(*value)[rapidjson::SizeType(i)]; + } -inline const JSValue* objectMember(const JSValue& value, const char * name) { - if (!value.HasMember(name)) { - return nullptr; + static bool isObject(const JSValue* value) { + return value->IsObject(); } - return &value[name]; -} -template <class Fn> -optional<Error> eachMember(const JSValue& value, Fn&& fn) { - assert(value.IsObject()); - for (const auto& property : value.GetObject()) { - optional<Error> result = - fn({ property.name.GetString(), property.name.GetStringLength() }, property.value); - if (result) { - return result; + static optional<const JSValue*> objectMember(const JSValue* value, const char * name) { + if (!value->HasMember(name)) { + return optional<const JSValue*>(); } + const JSValue* const& member = &(*value)[name]; + return {member}; } - return {}; -} -inline optional<bool> toBool(const JSValue& value) { - if (!value.IsBool()) { + template <class Fn> + static optional<Error> eachMember(const JSValue* value, Fn&& fn) { + assert(value->IsObject()); + for (const auto& property : value->GetObject()) { + optional<Error> result = + fn({ property.name.GetString(), property.name.GetStringLength() }, &property.value); + if (result) { + return result; + } + } return {}; } - return value.GetBool(); -} -inline optional<float> toNumber(const JSValue& value) { - if (!value.IsNumber()) { - return {}; + static optional<bool> toBool(const JSValue* value) { + if (!value->IsBool()) { + return {}; + } + return value->GetBool(); } - return value.GetDouble(); -} -inline optional<double> toDouble(const JSValue& value) { - if (!value.IsNumber()) { - return {}; + static optional<float> toNumber(const JSValue* value) { + if (!value->IsNumber()) { + return {}; + } + return value->GetDouble(); } - return value.GetDouble(); -} -inline optional<std::string> toString(const JSValue& value) { - if (!value.IsString()) { - return {}; + static optional<double> toDouble(const JSValue* value) { + if (!value->IsNumber()) { + return {}; + } + return value->GetDouble(); + } + + static optional<std::string> toString(const JSValue* value) { + if (!value->IsString()) { + return {}; + } + return {{ value->GetString(), value->GetStringLength() }}; } - return {{ value.GetString(), value.GetStringLength() }}; -} -inline optional<Value> toValue(const JSValue& value) { - switch (value.GetType()) { - case rapidjson::kNullType: - case rapidjson::kFalseType: - return { false }; + static optional<Value> toValue(const JSValue* value) { + switch (value->GetType()) { + case rapidjson::kNullType: + case rapidjson::kFalseType: + return { false }; - case rapidjson::kTrueType: - return { true }; + case rapidjson::kTrueType: + return { true }; - case rapidjson::kStringType: - return { std::string { value.GetString(), value.GetStringLength() } }; + 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() }; + case rapidjson::kNumberType: + if (value->IsUint64()) return { value->GetUint64() }; + if (value->IsInt64()) return { value->GetInt64() }; + return { value->GetDouble() }; - default: + default: + return {}; + } + } + + static optional<GeoJSON> toGeoJSON(const JSValue* value, Error& error) { + try { + return mapbox::geojson::convert(*value); + } catch (const std::exception& ex) { + error = { ex.what() }; return {}; + } } +}; + +template <class T, class...Args> +optional<T> convert(const JSValue& value, Error& error, Args&&...args) { + return convert<T>(Convertible(&value), error, std::forward<Args>(args)...); } } // namespace conversion } // namespace style } // namespace mbgl + diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp index 37907d3f60..3214c6316e 100644 --- a/src/mbgl/style/style_impl.cpp +++ b/src/mbgl/style/style_impl.cpp @@ -204,9 +204,10 @@ Layer* Style::Impl::addLayer(std::unique_ptr<Layer> layer, optional<std::string> } layer->setObserver(this); + Layer* result = layers.add(std::move(layer), before); observer->onUpdate(); - return layers.add(std::move(layer), before); + return result; } std::unique_ptr<Layer> Style::Impl::removeLayer(const std::string& id) { diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp index d648d2e5ff..bbec899950 100644 --- a/src/mbgl/tile/geojson_tile.cpp +++ b/src/mbgl/tile/geojson_tile.cpp @@ -23,19 +23,19 @@ void GeoJSONTile::querySourceFeatures( const SourceQueryOptions& options) { // Ignore the sourceLayer, there is only one - auto layer = getData()->getLayer({}); - - if (layer) { - auto featureCount = layer->featureCount(); - for (std::size_t i = 0; i < featureCount; i++) { - auto feature = layer->getFeature(i); - - // Apply filter, if any - if (options.filter && !(*options.filter)(*feature)) { - continue; + if (auto tileData = getData()) { + if (auto layer = tileData->getLayer({})) { + auto featureCount = layer->featureCount(); + for (std::size_t i = 0; i < featureCount; i++) { + auto feature = layer->getFeature(i); + + // Apply filter, if any + if (options.filter && !(*options.filter)(*feature)) { + continue; + } + + result.push_back(convertFeature(*feature, id.canonical)); } - - result.push_back(convertFeature(*feature, id.canonical)); } } } diff --git a/src/mbgl/tile/tile_id.hpp b/src/mbgl/tile/tile_id.hpp deleted file mode 100644 index 811158e9b9..0000000000 --- a/src/mbgl/tile/tile_id.hpp +++ /dev/null @@ -1,276 +0,0 @@ -#pragma once - -#include <mbgl/util/constants.hpp> - -#include <cstdint> -#include <array> -#include <forward_list> -#include <algorithm> -#include <iosfwd> -#include <cassert> -#include <boost/functional/hash.hpp> - -namespace mbgl { - -class OverscaledTileID; -class CanonicalTileID; -class UnwrappedTileID; - -// Has integer z/x/y coordinates -// All tiles must be derived from 0/0/0 (=no tiles outside of the main tile pyramid) -// Used for requesting data; represents data tiles that exist out there. -// z is never larger than the source's maxzoom -class CanonicalTileID { -public: - CanonicalTileID(uint8_t z, uint32_t x, uint32_t y); - bool operator==(const CanonicalTileID&) const; - bool operator!=(const CanonicalTileID&) const; - bool operator<(const CanonicalTileID&) const; - bool isChildOf(const CanonicalTileID&) const; - CanonicalTileID scaledTo(uint8_t z) const; - std::array<CanonicalTileID, 4> children() const; - - const uint8_t z; - const uint32_t x; - const uint32_t y; -}; - -::std::ostream& operator<<(::std::ostream& os, const CanonicalTileID& rhs); -namespace util { -std::string toString(const CanonicalTileID&); -} // namespace util - -// Has integer z/x/y coordinates -// overscaledZ describes the zoom level this tile is intented to represent, e.g. when parsing data -// z is never larger than the source's maxzoom -// z/x/y describe the -class OverscaledTileID { -public: - OverscaledTileID(uint8_t overscaledZ, int16_t wrap, CanonicalTileID); - OverscaledTileID(uint8_t overscaledZ, int16_t wrap, uint8_t z, uint32_t x, uint32_t y); - OverscaledTileID(uint8_t z, uint32_t x, uint32_t y); - explicit OverscaledTileID(const CanonicalTileID&); - explicit OverscaledTileID(CanonicalTileID&&); - bool operator==(const OverscaledTileID&) const; - bool operator!=(const OverscaledTileID&) const; - bool operator<(const OverscaledTileID&) const; - bool isChildOf(const OverscaledTileID&) const; - uint32_t overscaleFactor() const; - OverscaledTileID scaledTo(uint8_t z) const; - UnwrappedTileID toUnwrapped() const; - - const uint8_t overscaledZ; - const int16_t wrap; - const CanonicalTileID canonical; -}; - -::std::ostream& operator<<(::std::ostream& os, const OverscaledTileID& rhs); -namespace util { -std::string toString(const OverscaledTileID&); -} // namespace util - -// Has integer z/x/y coordinates -// wrap describes tiles that are left/right of the main tile pyramid, e.g. when wrapping the world -// Used for describing what position tiles are getting rendered at (= calc the matrix) -// z is never larger than the source's maxzoom -class UnwrappedTileID { -public: - UnwrappedTileID(uint8_t z, int64_t x, int64_t y); - UnwrappedTileID(int16_t wrap, CanonicalTileID); - bool operator==(const UnwrappedTileID&) const; - bool operator!=(const UnwrappedTileID&) const; - bool operator<(const UnwrappedTileID&) const; - bool isChildOf(const UnwrappedTileID&) const; - std::array<UnwrappedTileID, 4> children() const; - OverscaledTileID overscaleTo(uint8_t z) const; - float pixelsToTileUnits(float pixelValue, float zoom) const; - - const int16_t wrap; - const CanonicalTileID canonical; -}; - -::std::ostream& operator<<(::std::ostream& os, const UnwrappedTileID& rhs); -namespace util { -std::string toString(const UnwrappedTileID&); -} // namespace util - -inline CanonicalTileID::CanonicalTileID(uint8_t z_, uint32_t x_, uint32_t y_) : z(z_), x(x_), y(y_) { - assert(z <= 32); - assert(x < (1ull << z)); - assert(y < (1ull << z)); -} - -inline bool CanonicalTileID::operator==(const CanonicalTileID& rhs) const { - return z == rhs.z && x == rhs.x && y == rhs.y; -} - -inline bool CanonicalTileID::operator!=(const CanonicalTileID& rhs) const { - return z != rhs.z || x != rhs.x || y != rhs.y; -} - -inline bool CanonicalTileID::operator<(const CanonicalTileID& rhs) const { - return std::tie(z, x, y) < std::tie(rhs.z, rhs.x, rhs.y); -} - -inline bool CanonicalTileID::isChildOf(const CanonicalTileID& parent) const { - // We're first testing for z == 0, to avoid a 32 bit shift, which is undefined. - return parent.z == 0 || - (parent.z < z && parent.x == (x >> (z - parent.z)) && parent.y == (y >> (z - parent.z))); -} - -inline CanonicalTileID CanonicalTileID::scaledTo(uint8_t targetZ) const { - if (targetZ <= z) { - return { targetZ, x >> (z - targetZ), y >> (z - targetZ) }; // parent or same - } else { - return { targetZ, x << (targetZ - z), y << (targetZ - z) }; // child - } -} - -inline std::array<CanonicalTileID, 4> CanonicalTileID::children() const { - const uint8_t childZ = z + 1; - const uint32_t childX = x * 2; - const uint32_t childY = y * 2; - return { { - { childZ, childX, childY }, - { childZ, childX, childY + 1 }, - { childZ, childX + 1, childY }, - { childZ, childX + 1, childY + 1 }, - } }; -} - -inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, int16_t wrap_, CanonicalTileID canonical_) - : overscaledZ(overscaledZ_), wrap(wrap_), canonical(std::move(canonical_)) { - assert(overscaledZ >= canonical.z); -} - -inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, int16_t wrap_, uint8_t z, uint32_t x, uint32_t y) - : overscaledZ(overscaledZ_), wrap(wrap_), canonical(z, x, y) { - assert(overscaledZ >= canonical.z); -} - -inline OverscaledTileID::OverscaledTileID(uint8_t z, uint32_t x, uint32_t y) - : overscaledZ(z), wrap(0), canonical(z, x, y) { -} - -inline OverscaledTileID::OverscaledTileID(const CanonicalTileID& canonical_) - : overscaledZ(canonical_.z), wrap(0), canonical(canonical_) { - assert(overscaledZ >= canonical.z); -} - -inline OverscaledTileID::OverscaledTileID(CanonicalTileID&& canonical_) - : overscaledZ(canonical_.z), wrap(0), canonical(std::forward<CanonicalTileID>(canonical_)) { - assert(overscaledZ >= canonical.z); -} - -inline bool OverscaledTileID::operator==(const OverscaledTileID& rhs) const { - return overscaledZ == rhs.overscaledZ && wrap == rhs.wrap &&canonical == rhs.canonical; -} - -inline bool OverscaledTileID::operator!=(const OverscaledTileID& rhs) const { - return overscaledZ != rhs.overscaledZ || wrap != rhs.wrap || canonical != rhs.canonical; -} - -inline bool OverscaledTileID::operator<(const OverscaledTileID& rhs) const { - return std::tie(overscaledZ, wrap, canonical) < std::tie(rhs.overscaledZ, rhs.wrap, rhs.canonical); -} - -inline uint32_t OverscaledTileID::overscaleFactor() const { - return 1u << (overscaledZ - canonical.z); -} - -inline bool OverscaledTileID::isChildOf(const OverscaledTileID& rhs) const { - return overscaledZ > rhs.overscaledZ && - (canonical == rhs.canonical || canonical.isChildOf(rhs.canonical)); -} - -inline OverscaledTileID OverscaledTileID::scaledTo(uint8_t z) const { - return { z, wrap, z >= canonical.z ? canonical : canonical.scaledTo(z) }; -} - -inline UnwrappedTileID OverscaledTileID::toUnwrapped() const { - return { wrap, canonical }; -} - -inline UnwrappedTileID::UnwrappedTileID(uint8_t z_, int64_t x_, int64_t y_) - : wrap((x_ < 0 ? x_ - (1ll << z_) + 1 : x_) / (1ll << z_)), - canonical( - z_, - static_cast<uint32_t>(x_ - wrap * (1ll << z_)), - y_ < 0 ? 0 : std::min(static_cast<uint32_t>(y_), static_cast<uint32_t>(1ull << z_) - 1)) { -} - -inline UnwrappedTileID::UnwrappedTileID(int16_t wrap_, CanonicalTileID canonical_) - : wrap(wrap_), canonical(std::move(canonical_)) { -} - -inline bool UnwrappedTileID::operator==(const UnwrappedTileID& rhs) const { - return wrap == rhs.wrap && canonical == rhs.canonical; -} - -inline bool UnwrappedTileID::operator!=(const UnwrappedTileID& rhs) const { - return wrap != rhs.wrap || canonical != rhs.canonical; -} - -inline bool UnwrappedTileID::operator<(const UnwrappedTileID& rhs) const { - return std::tie(wrap, canonical) < std::tie(rhs.wrap, rhs.canonical); -} - -inline bool UnwrappedTileID::isChildOf(const UnwrappedTileID& parent) const { - return wrap == parent.wrap && canonical.isChildOf(parent.canonical); -} - -inline std::array<UnwrappedTileID, 4> UnwrappedTileID::children() const { - const uint8_t childZ = canonical.z + 1; - const uint32_t childX = canonical.x * 2; - const uint32_t childY = canonical.y * 2; - return { { - { wrap, { childZ, childX, childY } }, - { wrap, { childZ, childX, childY + 1 } }, - { wrap, { childZ, childX + 1, childY } }, - { wrap, { childZ, childX + 1, childY + 1 } }, - } }; -} - -inline OverscaledTileID UnwrappedTileID::overscaleTo(const uint8_t overscaledZ) const { - assert(overscaledZ >= canonical.z); - return { overscaledZ, wrap, canonical }; -} - -inline float UnwrappedTileID::pixelsToTileUnits(const float pixelValue, const float zoom) const { - return pixelValue * (util::EXTENT / (util::tileSize * std::pow(2, zoom - canonical.z))); -} - -} // namespace mbgl - -namespace std { - -template <> struct hash<mbgl::CanonicalTileID> { - size_t operator()(const mbgl::CanonicalTileID &id) const { - std::size_t seed = 0; - boost::hash_combine(seed, id.x); - boost::hash_combine(seed, id.y); - boost::hash_combine(seed, id.z); - return seed; - } -}; - -template <> struct hash<mbgl::UnwrappedTileID> { - size_t operator()(const mbgl::UnwrappedTileID &id) const { - std::size_t seed = 0; - boost::hash_combine(seed, std::hash<mbgl::CanonicalTileID>{}(id.canonical)); - boost::hash_combine(seed, id.wrap); - return seed; - } -}; - -template <> struct hash<mbgl::OverscaledTileID> { - size_t operator()(const mbgl::OverscaledTileID &id) const { - std::size_t seed = 0; - boost::hash_combine(seed, std::hash<mbgl::CanonicalTileID>{}(id.canonical)); - boost::hash_combine(seed, id.overscaledZ); - return seed; - } -}; - -} // namespace std - diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp deleted file mode 100644 index 572f46080e..0000000000 --- a/src/mbgl/util/thread.hpp +++ /dev/null @@ -1,163 +0,0 @@ -#pragma once - -#include <mbgl/actor/actor.hpp> -#include <mbgl/actor/mailbox.hpp> -#include <mbgl/actor/scheduler.hpp> -#include <mbgl/util/platform.hpp> -#include <mbgl/util/run_loop.hpp> -#include <mbgl/util/util.hpp> - -#include <cassert> -#include <future> -#include <memory> -#include <mutex> -#include <queue> -#include <string> -#include <thread> -#include <utility> - -namespace mbgl { -namespace util { - -// Manages a thread with `Object`. - -// Upon creation of this object, it launches a thread and creates an object of type `Object` -// in that thread. When the `Thread<>` object is destructed, the destructor waits -// for thread termination. The `Thread<>` constructor blocks until the thread and -// the `Object` are fully created, so after the object creation, it's safe to obtain the -// `Object` stored in this thread. The thread created will always have low priority on -// the platforms that support setting thread priority. -// -// The following properties make this class different from `ThreadPool`: -// -// - Only one thread is created. -// - `Object` will live in a single thread, providing thread affinity. -// - It is safe to use `ThreadLocal` in an `Object` managed by `Thread<>` -// - A `RunLoop` is created for the `Object` thread. -// - `Object` can use `Timer` and do asynchronous I/O, like wait for sockets events. -// -template<class Object> -class Thread : public Scheduler { -public: - template <class... Args> - Thread(const std::string& name, Args&&... args) { - std::promise<void> running; - - thread = std::thread([&] { - platform::setCurrentThreadName(name); - platform::makeThreadLowPriority(); - - util::RunLoop loop_(util::RunLoop::Type::New); - loop = &loop_; - - object = std::make_unique<Actor<Object>>(*this, std::forward<Args>(args)...); - running.set_value(); - - loop->run(); - loop = nullptr; - }); - - running.get_future().get(); - } - - ~Thread() override { - MBGL_VERIFY_THREAD(tid); - - if (paused) { - resume(); - } - - std::promise<void> joinable; - - // Kill the actor, so we don't get more - // messages posted on this scheduler after - // we delete the RunLoop. - loop->invoke([&] { - object.reset(); - joinable.set_value(); - }); - - joinable.get_future().get(); - - loop->stop(); - thread.join(); - } - - // Returns a non-owning reference to `Object` that - // can be used to send messages to `Object`. It is safe - // to the non-owning reference to outlive this object - // and be used after the `Thread<>` gets destroyed. - ActorRef<std::decay_t<Object>> actor() const { - return object->self(); - } - - // Pauses the `Object` thread. It will prevent the object to wake - // up from events such as timers and file descriptor I/O. Messages - // sent to a paused `Object` will be queued and only processed after - // `resume()` is called. - void pause() { - MBGL_VERIFY_THREAD(tid); - - assert(!paused); - - paused = std::make_unique<std::promise<void>>(); - resumed = std::make_unique<std::promise<void>>(); - - auto pausing = paused->get_future(); - - loop->invoke([this] { - auto resuming = resumed->get_future(); - paused->set_value(); - resuming.get(); - }); - - pausing.get(); - } - - // Resumes the `Object` thread previously paused by `pause()`. - void resume() { - MBGL_VERIFY_THREAD(tid); - - assert(paused); - - resumed->set_value(); - - resumed.reset(); - paused.reset(); - } - -private: - MBGL_STORE_THREAD(tid); - - void schedule(std::weak_ptr<Mailbox> mailbox) override { - { - std::lock_guard<std::mutex> lock(mutex); - queue.push(mailbox); - } - - loop->invoke([this] { receive(); }); - } - - void receive() { - std::unique_lock<std::mutex> lock(mutex); - - auto mailbox = queue.front(); - queue.pop(); - lock.unlock(); - - Mailbox::maybeReceive(mailbox); - } - - std::mutex mutex; - std::queue<std::weak_ptr<Mailbox>> queue; - std::thread thread; - std::unique_ptr<Actor<Object>> object; - - std::unique_ptr<std::promise<void>> paused; - std::unique_ptr<std::promise<void>> resumed; - - util::RunLoop* loop = nullptr; -}; - -} // namespace util -} // namespace mbgl diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp index c81becb986..39b562d811 100644 --- a/src/mbgl/util/tile_cover.cpp +++ b/src/mbgl/util/tile_cover.cpp @@ -182,10 +182,10 @@ uint64_t tileCount(const LatLngBounds& bounds, uint8_t zoom, uint16_t tileSize_) auto y1 = floor(sw.y/ tileSize_); auto y2 = floor((ne.y - 1) / tileSize_); - auto minX = std::fmax(std::min(x1, x2), 0); + auto minX = ::fmax(std::min(x1, x2), 0); auto maxX = std::max(x1, x2); auto minY = (std::pow(2, zoom) - 1) - std::max(y1, y2); - auto maxY = (std::pow(2, zoom) - 1) - std::fmax(std::min(y1, y2), 0); + auto maxY = (std::pow(2, zoom) - 1) - ::fmax(std::min(y1, y2), 0); return (maxX - minX + 1) * (maxY - minY + 1); } |