diff options
Diffstat (limited to 'src/mbgl')
44 files changed, 420 insertions, 488 deletions
diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp index 507cc7b087..f64989d661 100644 --- a/src/mbgl/geometry/line_atlas.cpp +++ b/src/mbgl/geometry/line_atlas.cpp @@ -4,6 +4,8 @@ #include <mbgl/platform/log.hpp> #include <mbgl/platform/platform.hpp> +#include <boost/functional/hash.hpp> + #include <sstream> #include <cmath> @@ -26,21 +28,22 @@ LineAtlas::~LineAtlas() { } LinePatternPos LineAtlas::getDashPosition(const std::vector<float> &dasharray, bool round) { - std::lock_guard<std::recursive_mutex> lock(mtx); - - std::ostringstream sskey; - - for (const float &part : dasharray) { - sskey << part << "-"; + size_t key = round ? std::numeric_limits<size_t>::min() : std::numeric_limits<size_t>::max(); + for (const float part : dasharray) { + boost::hash_combine<float>(key, part); } - sskey << round; - std::string key = sskey.str(); - if (positions.find(key) == positions.end()) { - positions[key] = addDash(dasharray, round); - } + // Note: We're not handling hash collisions here. - return positions[key]; + std::lock_guard<std::recursive_mutex> lock(mtx); + const auto it = positions.find(key); + if (it == positions.end()) { + auto inserted = positions.emplace(key, addDash(dasharray, round)); + assert(inserted.second); + return inserted.first->second; + } else { + return it->second; + } } LinePatternPos LineAtlas::addDash(const std::vector<float> &dasharray, bool round) { @@ -55,7 +58,7 @@ LinePatternPos LineAtlas::addDash(const std::vector<float> &dasharray, bool roun } float length = 0; - for (const float &part : dasharray) { + for (const float part : dasharray) { length += part; } diff --git a/src/mbgl/geometry/line_atlas.hpp b/src/mbgl/geometry/line_atlas.hpp index 191dc0c4d4..df60a2dec5 100644 --- a/src/mbgl/geometry/line_atlas.hpp +++ b/src/mbgl/geometry/line_atlas.hpp @@ -33,7 +33,7 @@ private: std::atomic<bool> dirty; uint32_t texture = 0; int nextRow = 0; - std::map<std::string, LinePatternPos> positions; + std::map<size_t, LinePatternPos> positions; }; }; diff --git a/src/mbgl/geometry/sprite_atlas.cpp b/src/mbgl/geometry/sprite_atlas.cpp index bf31c6e38e..c2686e2f34 100644 --- a/src/mbgl/geometry/sprite_atlas.cpp +++ b/src/mbgl/geometry/sprite_atlas.cpp @@ -73,7 +73,7 @@ Rect<SpriteAtlas::dimension> SpriteAtlas::allocateImage(const size_t pixel_width // This is so we can scale down the texture coordinates and pack them // into 2 bytes rather than 4 bytes. const uint16_t pack_width = (pixel_width + 1) + (4 - (pixel_width + 1) % 4); - const uint16_t pack_height = (pixel_height + 1) + (4 - (pixel_width + 1) % 4); + const uint16_t pack_height = (pixel_height + 1) + (4 - (pixel_height + 1) % 4); // We have to allocate a new area in the bin, and store an empty image in it. // Add a 1px border around every image. @@ -165,37 +165,37 @@ void SpriteAtlas::copy(const Rect<dimension>& dst, const SpritePosition& src, co static_cast<uint32_t>(dst.originalW * pixelRatio), static_cast<uint32_t>(dst.originalH * pixelRatio) }; - util::bilinearScale(srcData, srcSize, srcPos, dstData, dstSize, dstPos); + util::bilinearScale(srcData, srcSize, srcPos, dstData, dstSize, dstPos, wrap); // Add borders around the copied image if required. if (wrap) { // We're copying from the same image so we don't have to scale again. const uint32_t border = 1; + const uint32_t borderX = dstPos.x != 0 ? border : 0; + const uint32_t borderY = dstPos.y != 0 ? border : 0; + // Left border - if (dstPos.x >= border) { - util::nearestNeighborScale( - dstData, dstSize, { dstPos.x + dstPos.w - border - 1, dstPos.y, border, dstPos.h }, - dstData, dstSize, { dstPos.x - border, dstPos.y, border, dstPos.h }); - } + util::nearestNeighborScale( + dstData, dstSize, { dstPos.x + dstPos.w - borderX, dstPos.y, borderX, dstPos.h }, + dstData, dstSize, { dstPos.x - borderX, dstPos.y, borderX, dstPos.h }); + // Right border util::nearestNeighborScale(dstData, dstSize, { dstPos.x, dstPos.y, border, dstPos.h }, dstData, dstSize, { dstPos.x + dstPos.w, dstPos.y, border, dstPos.h }); // Top border - if (dstPos.y >= border) { - util::nearestNeighborScale( - dstData, dstSize, { dstPos.x - border, dstPos.y + dstPos.h - border - 1, - dstPos.w + 2 * border, border }, - dstData, dstSize, - { dstPos.x - border, dstPos.y - border, dstPos.w + 2 * border, border }); - } + util::nearestNeighborScale( + dstData, dstSize, { dstPos.x - borderX, dstPos.y + dstPos.h - borderY, + dstPos.w + border + borderX, borderY }, + dstData, dstSize, + { dstPos.x - borderX, dstPos.y - borderY, dstPos.w + 2 * borderX, borderY }); // Bottom border util::nearestNeighborScale( - dstData, dstSize, { dstPos.x - border, dstPos.y, dstPos.w + 2 * border, border }, + dstData, dstSize, { dstPos.x - borderX, dstPos.y, dstPos.w + 2 * borderX, border }, dstData, dstSize, - { dstPos.x - border, dstPos.y + dstPos.h, dstPos.w + 2 * border, border }); + { dstPos.x - borderX, dstPos.y + dstPos.h, dstPos.w + border + borderX, border }); } dirty = true; diff --git a/src/mbgl/geometry/static_vertex_buffer.cpp b/src/mbgl/geometry/static_vertex_buffer.cpp index c86211c50f..c1e8caab9e 100644 --- a/src/mbgl/geometry/static_vertex_buffer.cpp +++ b/src/mbgl/geometry/static_vertex_buffer.cpp @@ -4,7 +4,7 @@ namespace mbgl { StaticVertexBuffer::StaticVertexBuffer(std::initializer_list<std::pair<int16_t, int16_t>> init) { - for (const std::pair<int16_t, int16_t> &vertex : init) { + for (const auto& vertex : init) { vertex_type *vertices = static_cast<vertex_type *>(addElement()); vertices[0] = vertex.first; vertices[1] = vertex.second; diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 24f72e8dca..c4ad6efc53 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -18,7 +18,6 @@ #include <mbgl/text/glyph_store.hpp> #include <mbgl/geometry/glyph_atlas.hpp> #include <mbgl/style/style_layer.hpp> -#include <mbgl/style/style_layer_group.hpp> #include <mbgl/style/style_bucket.hpp> #include <mbgl/util/texture_pool.hpp> #include <mbgl/geometry/sprite_atlas.hpp> @@ -129,14 +128,22 @@ void Map::start(bool startPaused) { // Remove all of these to make sure they are destructed in the correct thread. style.reset(); + + // Since we don't have a stylesheet anymore, this will disable all Sources and cancel + // their associated requests. + updateSources(); + assert(activeSources.empty()); + + // It's now safe to destroy/join the workers since there won't be any more callbacks that + // could dispatch to the worker pool. workers.reset(); - activeSources.clear(); terminating = true; // Closes all open handles on the loop. This means that the loop will automatically terminate. asyncRender.reset(); asyncUpdate.reset(); + asyncInvoke.reset(); asyncTerminate.reset(); }); @@ -144,6 +151,10 @@ void Map::start(bool startPaused) { update(); }); + asyncInvoke = util::make_unique<uv::async>(env->loop, [this] { + processTasks(); + }); + asyncRender = util::make_unique<uv::async>(env->loop, [this] { // Must be called in Map thread. assert(Environment::currentlyOn(ThreadType::Map)); @@ -315,6 +326,42 @@ void Map::triggerRender() { asyncRender->send(); } +// Runs the function in the map thread. +void Map::invokeTask(std::function<void()>&& fn) { + { + std::lock_guard<std::mutex> lock(mutexTask); + tasks.emplace(::std::forward<std::function<void()>>(fn)); + } + + // TODO: Once we have aligned static and continuous rendering, this should always dispatch + // to the async queue. + if (asyncInvoke) { + asyncInvoke->send(); + } else { + processTasks(); + } +} + +template <typename Fn> auto Map::invokeSyncTask(const Fn& fn) -> decltype(fn()) { + std::promise<decltype(fn())> promise; + invokeTask([&fn, &promise] { promise.set_value(fn()); }); + return promise.get_future().get(); +} + +// Processes the functions that should be run in the map thread. +void Map::processTasks() { + std::queue<std::function<void()>> queue; + { + std::lock_guard<std::mutex> lock(mutexTask); + queue.swap(tasks); + } + + while (!queue.empty()) { + queue.front()(); + queue.pop(); + } +} + void Map::checkForPause() { std::unique_lock<std::mutex> lockRun (mutexRun); while (pausing) { @@ -352,13 +399,15 @@ void Map::setup() { void Map::setStyleURL(const std::string &url) { assert(Environment::currentlyOn(ThreadType::Main)); - const size_t pos = url.rfind('/'); + const std::string styleURL = mbgl::util::mapbox::normalizeStyleURL(url, getAccessToken()); + + const size_t pos = styleURL.rfind('/'); std::string base = ""; if (pos != std::string::npos) { - base = url.substr(0, pos + 1); + base = styleURL.substr(0, pos + 1); } - data->setStyleInfo({ url, base, "" }); + data->setStyleInfo({ styleURL, base, "" }); triggerUpdate(Update::StyleInfo); } @@ -542,21 +591,31 @@ std::string Map::getAccessToken() const { void Map::setDefaultPointAnnotationSymbol(const std::string& symbol) { assert(Environment::currentlyOn(ThreadType::Main)); - annotationManager->setDefaultPointAnnotationSymbol(symbol); + invokeTask([=] { + annotationManager->setDefaultPointAnnotationSymbol(symbol); + }); } -uint32_t Map::addPointAnnotation(const LatLng& point, const std::string& symbol) { +double Map::getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol) { assert(Environment::currentlyOn(ThreadType::Main)); - std::vector<LatLng> points({ point }); - std::vector<std::string> symbols({ symbol }); - return addPointAnnotations(points, symbols)[0]; + return invokeSyncTask([&] { + assert(sprite); + const SpritePosition pos = sprite->getSpritePosition(symbol); + return -pos.height / pos.pixelRatio / 2; + }); +} + +uint32_t Map::addPointAnnotation(const LatLng& point, const std::string& symbol) { + return addPointAnnotations({ point }, { symbol }).front(); } std::vector<uint32_t> Map::addPointAnnotations(const std::vector<LatLng>& points, const std::vector<std::string>& symbols) { assert(Environment::currentlyOn(ThreadType::Main)); - auto result = annotationManager->addPointAnnotations(points, symbols, *this); - updateAnnotationTiles(result.first); - return result.second; + return invokeSyncTask([&] { + auto result = annotationManager->addPointAnnotations(points, symbols, *this); + updateAnnotationTiles(result.first); + return result.second; + }); } void Map::removeAnnotation(uint32_t annotation) { @@ -566,22 +625,28 @@ void Map::removeAnnotation(uint32_t annotation) { void Map::removeAnnotations(const std::vector<uint32_t>& annotations) { assert(Environment::currentlyOn(ThreadType::Main)); - auto result = annotationManager->removeAnnotations(annotations, *this); - updateAnnotationTiles(result); + invokeTask([=] { + auto result = annotationManager->removeAnnotations(annotations, *this); + updateAnnotationTiles(result); + }); } -std::vector<uint32_t> Map::getAnnotationsInBounds(const LatLngBounds& bounds) const { +std::vector<uint32_t> Map::getAnnotationsInBounds(const LatLngBounds& bounds) { assert(Environment::currentlyOn(ThreadType::Main)); - return annotationManager->getAnnotationsInBounds(bounds, *this); + return invokeSyncTask([&] { + return annotationManager->getAnnotationsInBounds(bounds, *this); + }); } -LatLngBounds Map::getBoundsForAnnotations(const std::vector<uint32_t>& annotations) const { +LatLngBounds Map::getBoundsForAnnotations(const std::vector<uint32_t>& annotations) { assert(Environment::currentlyOn(ThreadType::Main)); - return annotationManager->getBoundsForAnnotations(annotations); + return invokeSyncTask([&] { + return annotationManager->getBoundsForAnnotations(annotations); + }); } void Map::updateAnnotationTiles(const std::vector<Tile::ID>& ids) { - assert(Environment::currentlyOn(ThreadType::Main)); + assert(Environment::currentlyOn(ThreadType::Map)); for (const auto &source : activeSources) { if (source->info.type == SourceType::Annotations) { source->source->invalidateTiles(*this, ids); @@ -657,7 +722,11 @@ void Map::updateSources() { // Then, reenable all of those that we actually use when drawing this layer. if (style) { - updateSources(style->layers); + for (const auto& layer : style->layers) { + if (layer->bucket && layer->bucket->style_source) { + (*activeSources.emplace(layer->bucket->style_source).first)->enabled = true; + } + } } // Then, construct or destroy the actual source object, depending on enabled state. @@ -678,23 +747,9 @@ void Map::updateSources() { }); } -void Map::updateSources(const util::ptr<StyleLayerGroup> &group) { - assert(Environment::currentlyOn(ThreadType::Map)); - if (!group) { - return; - } - for (const util::ptr<StyleLayer> &layer : group->layers) { - if (!layer) continue; - if (layer->bucket && layer->bucket->style_source) { - (*activeSources.emplace(layer->bucket->style_source).first)->enabled = true; - } - - } -} - void Map::updateTiles() { assert(Environment::currentlyOn(ThreadType::Map)); - for (const auto &source : activeSources) { + for (const auto& source : activeSources) { source->source->update(*this, getWorker(), style, *glyphAtlas, *glyphStore, *spriteAtlas, getSprite(), *texturePool, [this]() { assert(Environment::currentlyOn(ThreadType::Map)); @@ -741,7 +796,7 @@ void Map::loadStyleJSON(const std::string& json, const std::string& base) { style = std::make_shared<Style>(); style->base = base; style->loadJSON((const uint8_t *)json.c_str()); - style->cascadeClasses(data->getClasses()); + style->cascade(data->getClasses()); style->setDefaultTransitionDuration(data->getDefaultTransitionDuration()); const std::string glyphURL = util::mapbox::normalizeGlyphsURL(style->glyph_url, getAccessToken()); @@ -754,7 +809,7 @@ void Map::prepare() { assert(Environment::currentlyOn(ThreadType::Map)); const auto u = updated.exchange(static_cast<UpdateType>(Update::Nothing)); - if (u & static_cast<UpdateType>(Update::StyleInfo)) { + if ((u & static_cast<UpdateType>(Update::StyleInfo)) || !style) { reloadStyle(); } if (u & static_cast<UpdateType>(Update::Debug)) { @@ -768,7 +823,7 @@ void Map::prepare() { } if (u & static_cast<UpdateType>(Update::Classes)) { if (style) { - style->cascadeClasses(data->getClasses()); + style->cascade(data->getClasses()); } } @@ -784,7 +839,7 @@ void Map::prepare() { if (style) { updateSources(); - style->updateProperties(state.getNormalizedZoom(), animationTime); + style->recalculate(state.getNormalizedZoom(), animationTime); // Allow the sprite atlas to potentially pull new sprite images if needed. spriteAtlas->resize(state.getPixelRatio()); @@ -804,6 +859,7 @@ void Map::render() { // Cleanup OpenGL objects that we abandoned since the last render call. env->performCleanup(); + assert(style); assert(painter); painter->render(*style, activeSources, state, data->getAnimationTime()); diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 8189068886..0cf74147e4 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -78,7 +78,7 @@ void Source::updateClipIDs(const std::map<Tile::ID, ClipID> &mapping) { } void Source::updateMatrices(const mat4 &projMatrix, const TransformState &transform) { - for (std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) { + for (const auto& pair : tiles) { Tile &tile = *pair.second; transform.matrixFor(tile.matrix, tile.id); matrix::multiply(tile.matrix, projMatrix, tile.matrix); @@ -90,7 +90,7 @@ size_t Source::getTileCount() const { } void Source::drawClippingMasks(Painter &painter) { - for (std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) { + for (const auto& pair : tiles) { Tile &tile = *pair.second; gl::group group(std::string { "mask: " } + std::string(tile.id)); painter.drawClippingMask(tile.matrix, tile.clip); @@ -99,7 +99,7 @@ void Source::drawClippingMasks(Painter &painter) { void Source::render(Painter &painter, const StyleLayer &layer_desc) { gl::group group(std::string { "layer: " } + layer_desc.id); - for (const std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) { + for (const auto& pair : tiles) { Tile &tile = *pair.second; if (tile.data && tile.data->state == TileData::State::parsed) { painter.renderTileLayer(tile, layer_desc, tile.matrix); @@ -115,7 +115,7 @@ void Source::render(Painter &painter, const StyleLayer &layer_desc, const Tile:: } void Source::finishRender(Painter &painter) { - for (std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) { + for (const auto& pair : tiles) { Tile &tile = *pair.second; painter.renderTileDebug(tile); } @@ -252,7 +252,7 @@ bool Source::findLoadedChildren(const Tile::ID& id, int32_t maxCoveringZoom, std bool complete = true; int32_t z = id.z; auto ids = id.children(z + 1); - for (const Tile::ID& child_id : ids) { + for (const auto& child_id : ids) { const TileData::State state = hasTile(child_id); if (state == TileData::State::parsed) { retain.emplace_front(child_id); @@ -301,8 +301,6 @@ void Source::update(Map &map, return; } - bool changed = false; - int32_t zoom = std::floor(getZoom(map.getState())); std::forward_list<Tile::ID> required = coveringTiles(map.getState()); @@ -316,7 +314,7 @@ void Source::update(Map &map, std::forward_list<Tile::ID> retain(required); // Add existing child/parent tiles if the actual tile is not yet loaded - for (const Tile::ID& id : required) { + for (const auto& id : required) { const TileData::State state = addTile(map, worker, style, glyphAtlas, glyphStore, spriteAtlas, sprite, texturePool, id, callback); @@ -334,21 +332,15 @@ void Source::update(Map &map, findLoadedParent(id, minCoveringZoom, retain); } } - - if (state == TileData::State::initial) { - changed = true; - } } // Remove tiles that we definitely don't need, i.e. tiles that are not on // the required list. std::set<Tile::ID> retain_data; - util::erase_if(tiles, [&retain, &retain_data, &changed](std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair) { + util::erase_if(tiles, [&retain, &retain_data](std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair) { Tile &tile = *pair.second; bool obsolete = std::find(retain.begin(), retain.end(), tile.id) == retain.end(); - if (obsolete) { - changed = true; - } else { + if (!obsolete) { retain_data.insert(tile.data->id); } return obsolete; diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/map/tile_data.hpp index cce346d835..a5598fee3b 100644 --- a/src/mbgl/map/tile_data.hpp +++ b/src/mbgl/map/tile_data.hpp @@ -9,8 +9,6 @@ #include <mbgl/util/ptr.hpp> #include <atomic> -#include <exception> -#include <iosfwd> #include <string> #include <functional> @@ -22,7 +20,6 @@ typedef struct uv_loop_s uv_loop_t; namespace mbgl { -class Map; class Environment; class Painter; class SourceInfo; @@ -32,12 +29,6 @@ class Request; class TileData : public std::enable_shared_from_this<TileData>, private util::noncopyable { public: - struct exception : std::exception {}; - struct geometry_too_long_exception : exception {}; - -public: - typedef util::ptr<TileData> Ptr; - enum class State { invalid, initial, @@ -47,7 +38,6 @@ public: obsolete }; -public: TileData(Tile::ID const &id, const SourceInfo &); ~TileData(); @@ -65,16 +55,14 @@ public: virtual void render(Painter &painter, const StyleLayer &layer_desc, const mat4 &matrix) = 0; virtual bool hasData(StyleLayer const &layer_desc) const = 0; -public: const Tile::ID id; const std::string name; std::atomic<State> state; -public: +protected: const SourceInfo& source; Environment& env; -protected: Request *req = nullptr; std::string data; diff --git a/src/mbgl/map/tile_parser.cpp b/src/mbgl/map/tile_parser.cpp index fa7f4c093f..bc6de40565 100644 --- a/src/mbgl/map/tile_parser.cpp +++ b/src/mbgl/map/tile_parser.cpp @@ -3,8 +3,7 @@ #include <mbgl/platform/log.hpp> #include <mbgl/style/style.hpp> #include <mbgl/style/style_layer.hpp> -#include <mbgl/style/style_layer_group.hpp> -#include <mbgl/style/style_layout.hpp> +#include <mbgl/style/style_source.hpp> #include <mbgl/renderer/fill_bucket.hpp> #include <mbgl/renderer/line_bucket.hpp> #include <mbgl/renderer/symbol_bucket.hpp> @@ -49,18 +48,10 @@ TileParser::TileParser(const GeometryTile& geometryTile_, assert(collision); } -void TileParser::parse() { - parseStyleLayers(style->layers); -} - bool TileParser::obsolete() const { return tile.state == TileData::State::obsolete; } -void TileParser::parseStyleLayers(util::ptr<const StyleLayerGroup> group) { - if (!group) { - return; - } - - for (const util::ptr<const StyleLayer> &layer_desc : group->layers) { +void TileParser::parse() { + for (const auto& layer_desc : style->layers) { // Cancel early when parsing. if (obsolete()) { return; @@ -122,65 +113,6 @@ void applyLayoutProperty(PropertyKey key, const ClassProperties &classProperties } } -std::unique_ptr<StyleLayoutFill> parseStyleLayoutFill(const StyleBucket &/*bucket*/, const float /*z*/) { - // no-op; Fill buckets don't currently have any applicable layout properties - auto fillPtr = util::make_unique<StyleLayoutFill>(); - return fillPtr; -} - -std::unique_ptr<StyleLayoutLine> parseStyleLayoutLine(const StyleBucket &bucket_desc, const float z) { - auto linePtr = util::make_unique<StyleLayoutLine>(); - auto &line = *linePtr; - applyLayoutProperty(PropertyKey::LineCap, bucket_desc.layout, line.cap, z); - applyLayoutProperty(PropertyKey::LineJoin, bucket_desc.layout, line.join, z); - applyLayoutProperty(PropertyKey::LineMiterLimit, bucket_desc.layout, line.miter_limit, z); - applyLayoutProperty(PropertyKey::LineRoundLimit, bucket_desc.layout, line.round_limit, z); - return linePtr; -} - -std::unique_ptr<StyleLayoutSymbol> parseStyleLayoutSymbol(const StyleBucket &bucket_desc, const float z) { - auto symbolPtr = util::make_unique<StyleLayoutSymbol>(); - auto &symbol = *symbolPtr; - applyLayoutProperty(PropertyKey::SymbolPlacement, bucket_desc.layout, symbol.placement, z); - if (symbol.placement == PlacementType::Line) { - symbol.icon.rotation_alignment = RotationAlignmentType::Map; - symbol.text.rotation_alignment = RotationAlignmentType::Map; - }; - applyLayoutProperty(PropertyKey::SymbolMinDistance, bucket_desc.layout, symbol.min_distance, z); - applyLayoutProperty(PropertyKey::SymbolAvoidEdges, bucket_desc.layout, symbol.avoid_edges, z); - - applyLayoutProperty(PropertyKey::IconAllowOverlap, bucket_desc.layout, symbol.icon.allow_overlap, z); - applyLayoutProperty(PropertyKey::IconIgnorePlacement, bucket_desc.layout, symbol.icon.ignore_placement, z); - applyLayoutProperty(PropertyKey::IconOptional, bucket_desc.layout, symbol.icon.optional, z); - applyLayoutProperty(PropertyKey::IconRotationAlignment, bucket_desc.layout, symbol.icon.rotation_alignment, z); - applyLayoutProperty(PropertyKey::IconMaxSize, bucket_desc.layout, symbol.icon.max_size, z); - applyLayoutProperty(PropertyKey::IconImage, bucket_desc.layout, symbol.icon.image, z); - applyLayoutProperty(PropertyKey::IconPadding, bucket_desc.layout, symbol.icon.padding, z); - applyLayoutProperty(PropertyKey::IconRotate, bucket_desc.layout, symbol.icon.rotate, z); - applyLayoutProperty(PropertyKey::IconKeepUpright, bucket_desc.layout, symbol.icon.keep_upright, z); - applyLayoutProperty(PropertyKey::IconOffset, bucket_desc.layout, symbol.icon.offset, z); - - applyLayoutProperty(PropertyKey::TextRotationAlignment, bucket_desc.layout, symbol.text.rotation_alignment, z); - applyLayoutProperty(PropertyKey::TextField, bucket_desc.layout, symbol.text.field, z); - applyLayoutProperty(PropertyKey::TextFont, bucket_desc.layout, symbol.text.font, z); - applyLayoutProperty(PropertyKey::TextMaxSize, bucket_desc.layout, symbol.text.max_size, z); - applyLayoutProperty(PropertyKey::TextMaxWidth, bucket_desc.layout, symbol.text.max_width, z); - applyLayoutProperty(PropertyKey::TextLineHeight, bucket_desc.layout, symbol.text.line_height, z); - applyLayoutProperty(PropertyKey::TextLetterSpacing, bucket_desc.layout, symbol.text.letter_spacing, z); - applyLayoutProperty(PropertyKey::TextMaxAngle, bucket_desc.layout, symbol.text.max_angle, z); - applyLayoutProperty(PropertyKey::TextRotate, bucket_desc.layout, symbol.text.rotate, z); - applyLayoutProperty(PropertyKey::TextPadding, bucket_desc.layout, symbol.text.padding, z); - applyLayoutProperty(PropertyKey::TextIgnorePlacement, bucket_desc.layout, symbol.text.ignore_placement, z); - applyLayoutProperty(PropertyKey::TextOptional, bucket_desc.layout, symbol.text.optional, z); - applyLayoutProperty(PropertyKey::TextJustify, bucket_desc.layout, symbol.text.justify, z); - applyLayoutProperty(PropertyKey::TextAnchor, bucket_desc.layout, symbol.text.anchor, z); - applyLayoutProperty(PropertyKey::TextKeepUpright, bucket_desc.layout, symbol.text.keep_upright, z); - applyLayoutProperty(PropertyKey::TextTransform, bucket_desc.layout, symbol.text.transform, z); - applyLayoutProperty(PropertyKey::TextOffset, bucket_desc.layout, symbol.text.offset, z); - applyLayoutProperty(PropertyKey::TextAllowOverlap, bucket_desc.layout, symbol.text.allow_overlap, z); - return symbolPtr; -} - std::unique_ptr<Bucket> TileParser::createBucket(const StyleBucket &bucketDesc) { // Skip this bucket if we are to not render this if (tile.id.z < std::floor(bucketDesc.min_zoom) && std::floor(bucketDesc.min_zoom) < tile.source.max_zoom) return nullptr; @@ -230,32 +162,78 @@ void TileParser::addBucketGeometries(Bucket& bucket, const GeometryTileLayer& la std::unique_ptr<Bucket> TileParser::createFillBucket(const GeometryTileLayer& layer, const StyleBucket& bucket_desc) { - auto fill = parseStyleLayoutFill(bucket_desc, tile.id.z); - auto bucket = util::make_unique<FillBucket>(std::move(fill), - tile.fillVertexBuffer, + auto bucket = util::make_unique<FillBucket>(tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer); addBucketGeometries(bucket, layer, bucket_desc.filter); - return obsolete() ? nullptr : std::move(bucket); + return std::move(bucket); } std::unique_ptr<Bucket> TileParser::createLineBucket(const GeometryTileLayer& layer, const StyleBucket& bucket_desc) { - auto line = parseStyleLayoutLine(bucket_desc, tile.id.z); - auto bucket = util::make_unique<LineBucket>(std::move(line), - tile.lineVertexBuffer, + auto bucket = util::make_unique<LineBucket>(tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer); + + const float z = tile.id.z; + auto& layout = bucket->layout; + + applyLayoutProperty(PropertyKey::LineCap, bucket_desc.layout, layout.cap, z); + applyLayoutProperty(PropertyKey::LineJoin, bucket_desc.layout, layout.join, z); + applyLayoutProperty(PropertyKey::LineMiterLimit, bucket_desc.layout, layout.miter_limit, z); + applyLayoutProperty(PropertyKey::LineRoundLimit, bucket_desc.layout, layout.round_limit, z); + addBucketGeometries(bucket, layer, bucket_desc.filter); - return obsolete() ? nullptr : std::move(bucket); + return std::move(bucket); } std::unique_ptr<Bucket> TileParser::createSymbolBucket(const GeometryTileLayer& layer, const StyleBucket& bucket_desc) { - auto symbol = parseStyleLayoutSymbol(bucket_desc, tile.id.z); - auto bucket = util::make_unique<SymbolBucket>(std::move(symbol), *collision); + auto bucket = util::make_unique<SymbolBucket>(*collision); + + const float z = tile.id.z; + auto& layout = bucket->layout; + + applyLayoutProperty(PropertyKey::SymbolPlacement, bucket_desc.layout, layout.placement, z); + if (layout.placement == PlacementType::Line) { + layout.icon.rotation_alignment = RotationAlignmentType::Map; + layout.text.rotation_alignment = RotationAlignmentType::Map; + }; + applyLayoutProperty(PropertyKey::SymbolMinDistance, bucket_desc.layout, layout.min_distance, z); + applyLayoutProperty(PropertyKey::SymbolAvoidEdges, bucket_desc.layout, layout.avoid_edges, z); + + applyLayoutProperty(PropertyKey::IconAllowOverlap, bucket_desc.layout, layout.icon.allow_overlap, z); + applyLayoutProperty(PropertyKey::IconIgnorePlacement, bucket_desc.layout, layout.icon.ignore_placement, z); + applyLayoutProperty(PropertyKey::IconOptional, bucket_desc.layout, layout.icon.optional, z); + applyLayoutProperty(PropertyKey::IconRotationAlignment, bucket_desc.layout, layout.icon.rotation_alignment, z); + applyLayoutProperty(PropertyKey::IconMaxSize, bucket_desc.layout, layout.icon.max_size, z); + applyLayoutProperty(PropertyKey::IconImage, bucket_desc.layout, layout.icon.image, z); + applyLayoutProperty(PropertyKey::IconPadding, bucket_desc.layout, layout.icon.padding, z); + applyLayoutProperty(PropertyKey::IconRotate, bucket_desc.layout, layout.icon.rotate, z); + applyLayoutProperty(PropertyKey::IconKeepUpright, bucket_desc.layout, layout.icon.keep_upright, z); + applyLayoutProperty(PropertyKey::IconOffset, bucket_desc.layout, layout.icon.offset, z); + + applyLayoutProperty(PropertyKey::TextRotationAlignment, bucket_desc.layout, layout.text.rotation_alignment, z); + applyLayoutProperty(PropertyKey::TextField, bucket_desc.layout, layout.text.field, z); + applyLayoutProperty(PropertyKey::TextFont, bucket_desc.layout, layout.text.font, z); + applyLayoutProperty(PropertyKey::TextMaxSize, bucket_desc.layout, layout.text.max_size, z); + applyLayoutProperty(PropertyKey::TextMaxWidth, bucket_desc.layout, layout.text.max_width, z); + applyLayoutProperty(PropertyKey::TextLineHeight, bucket_desc.layout, layout.text.line_height, z); + applyLayoutProperty(PropertyKey::TextLetterSpacing, bucket_desc.layout, layout.text.letter_spacing, z); + applyLayoutProperty(PropertyKey::TextMaxAngle, bucket_desc.layout, layout.text.max_angle, z); + applyLayoutProperty(PropertyKey::TextRotate, bucket_desc.layout, layout.text.rotate, z); + applyLayoutProperty(PropertyKey::TextPadding, bucket_desc.layout, layout.text.padding, z); + applyLayoutProperty(PropertyKey::TextIgnorePlacement, bucket_desc.layout, layout.text.ignore_placement, z); + applyLayoutProperty(PropertyKey::TextOptional, bucket_desc.layout, layout.text.optional, z); + applyLayoutProperty(PropertyKey::TextJustify, bucket_desc.layout, layout.text.justify, z); + applyLayoutProperty(PropertyKey::TextAnchor, bucket_desc.layout, layout.text.anchor, z); + applyLayoutProperty(PropertyKey::TextKeepUpright, bucket_desc.layout, layout.text.keep_upright, z); + applyLayoutProperty(PropertyKey::TextTransform, bucket_desc.layout, layout.text.transform, z); + applyLayoutProperty(PropertyKey::TextOffset, bucket_desc.layout, layout.text.offset, z); + applyLayoutProperty(PropertyKey::TextAllowOverlap, bucket_desc.layout, layout.text.allow_overlap, z); + bucket->addFeatures( layer, bucket_desc.filter, reinterpret_cast<uintptr_t>(&tile), spriteAtlas, *sprite, glyphAtlas, glyphStore); - return obsolete() ? nullptr : std::move(bucket); + return std::move(bucket); } } diff --git a/src/mbgl/map/tile_parser.hpp b/src/mbgl/map/tile_parser.hpp index 0ad42fdc91..2c16d2a2fd 100644 --- a/src/mbgl/map/tile_parser.hpp +++ b/src/mbgl/map/tile_parser.hpp @@ -28,7 +28,6 @@ class StyleLayoutFill; class StyleLayoutRaster; class StyleLayoutLine; class StyleLayoutSymbol; -class StyleLayerGroup; class VectorTileData; class Collision; @@ -48,7 +47,6 @@ public: private: bool obsolete() const; - void parseStyleLayers(util::ptr<const StyleLayerGroup> group); std::unique_ptr<Bucket> createBucket(const StyleBucket&); std::unique_ptr<Bucket> createFillBucket(const GeometryTileLayer&, const StyleBucket&); @@ -58,7 +56,6 @@ private: template <class Bucket> void addBucketGeometries(Bucket&, const GeometryTileLayer&, const FilterExpression&); -private: const GeometryTile& geometryTile; VectorTileData& tile; diff --git a/src/mbgl/map/vector_tile.cpp b/src/mbgl/map/vector_tile.cpp index dca2168a47..01d52a348a 100644 --- a/src/mbgl/map/vector_tile.cpp +++ b/src/mbgl/map/vector_tile.cpp @@ -35,26 +35,7 @@ VectorTileFeature::VectorTileFeature(pbf feature_pbf, const VectorTileLayer& lay if (feature_pbf.tag == 1) { // id id = feature_pbf.varint<uint64_t>(); } else if (feature_pbf.tag == 2) { // tags - // tags are packed varints. They should have an even length. - pbf tags = feature_pbf.message(); - while (tags) { - uint32_t tag_key = tags.varint(); - - if (layer.keys.size() <= tag_key) { - throw std::runtime_error("feature referenced out of range key"); - } - - if (!tags) { - throw std::runtime_error("uneven number of feature tag ids"); - } - - uint32_t tag_val = tags.varint(); - if (layer.values.size() <= tag_val) { - throw std::runtime_error("feature referenced out of range value"); - } - - properties.emplace(tag_key, tag_val); - } + tags_pbf = feature_pbf.message(); } else if (feature_pbf.tag == 3) { // type type = (FeatureType)feature_pbf.varint(); } else if (feature_pbf.tag == 4) { // geometry @@ -70,11 +51,30 @@ mapbox::util::optional<Value> VectorTileFeature::getValue(const std::string& key if (keyIter == layer.keys.end()) { return mapbox::util::optional<Value>(); } - auto propIter = properties.find(keyIter->second); - if (propIter == properties.end()) { - return mapbox::util::optional<Value>(); + + pbf tags = tags_pbf; + while (tags) { + uint32_t tag_key = tags.varint(); + + if (layer.keys.size() <= tag_key) { + throw std::runtime_error("feature referenced out of range key"); + } + + if (!tags) { + throw std::runtime_error("uneven number of feature tag ids"); + } + + uint32_t tag_val = tags.varint(); + if (layer.values.size() <= tag_val) { + throw std::runtime_error("feature referenced out of range value"); + } + + if (tag_key == keyIter->second) { + return layer.values[tag_val]; + } } - return layer.values[propIter->second]; + + return mapbox::util::optional<Value>(); } GeometryCollection VectorTileFeature::getGeometries() const { diff --git a/src/mbgl/map/vector_tile.hpp b/src/mbgl/map/vector_tile.hpp index 9a23c3b189..77a0b4ab16 100644 --- a/src/mbgl/map/vector_tile.hpp +++ b/src/mbgl/map/vector_tile.hpp @@ -22,7 +22,7 @@ private: const VectorTileLayer& layer; uint64_t id = 0; FeatureType type = FeatureType::Unknown; - std::unordered_map<uint32_t, uint32_t> properties; + pbf tags_pbf; pbf geometry_pbf; }; diff --git a/src/mbgl/renderer/debug_bucket.cpp b/src/mbgl/renderer/debug_bucket.cpp index 3c56401e1e..6104e2456b 100644 --- a/src/mbgl/renderer/debug_bucket.cpp +++ b/src/mbgl/renderer/debug_bucket.cpp @@ -5,8 +5,6 @@ #include <cassert> -struct geometry_too_long_exception : std::exception {}; - using namespace mbgl; DebugBucket::DebugBucket(DebugFontBuffer& fontBuffer_) diff --git a/src/mbgl/renderer/fill_bucket.cpp b/src/mbgl/renderer/fill_bucket.cpp index 26d0d1f4be..958ea3d998 100644 --- a/src/mbgl/renderer/fill_bucket.cpp +++ b/src/mbgl/renderer/fill_bucket.cpp @@ -28,12 +28,10 @@ void FillBucket::free(void *, void *ptr) { ::free(ptr); } -FillBucket::FillBucket(std::unique_ptr<const StyleLayoutFill> styleLayout_, - FillVertexBuffer &vertexBuffer_, +FillBucket::FillBucket(FillVertexBuffer &vertexBuffer_, TriangleElementsBuffer &triangleElementsBuffer_, LineElementsBuffer &lineElementsBuffer_) - : styleLayout(std::move(styleLayout_)), - allocator(new TESSalloc{ + : allocator(new TESSalloc{ &alloc, &realloc, &free, @@ -53,7 +51,6 @@ FillBucket::FillBucket(std::unique_ptr<const StyleLayoutFill> styleLayout_, triangle_elements_start(triangleElementsBuffer_.index()), line_elements_start(lineElementsBuffer.index()) { assert(tesselator); - assert(styleLayout); } FillBucket::~FillBucket() { @@ -95,7 +92,7 @@ void FillBucket::tessellate() { } size_t total_vertex_count = 0; - for (const std::vector<ClipperLib::IntPoint>& polygon : polygons) { + for (const auto& polygon : polygons) { total_vertex_count += polygon.size(); } @@ -112,12 +109,12 @@ void FillBucket::tessellate() { line_group_type& lineGroup = *lineGroups.back(); uint32_t lineIndex = lineGroup.vertex_length; - for (const std::vector<ClipperLib::IntPoint>& polygon : polygons) { + for (const auto& polygon : polygons) { const size_t group_count = polygon.size(); assert(group_count >= 3); std::vector<TESSreal> clipped_line; - for (const ClipperLib::IntPoint& pt : polygon) { + for (const auto& pt : polygon) { clipped_line.push_back(pt.X); clipped_line.push_back(pt.Y); vertexBuffer.add(pt.X, pt.Y); diff --git a/src/mbgl/renderer/fill_bucket.hpp b/src/mbgl/renderer/fill_bucket.hpp index 46b8f53857..937fd540ac 100644 --- a/src/mbgl/renderer/fill_bucket.hpp +++ b/src/mbgl/renderer/fill_bucket.hpp @@ -6,6 +6,7 @@ #include <mbgl/geometry/elements_buffer.hpp> #include <mbgl/geometry/fill_buffer.hpp> #include <mbgl/style/style_bucket.hpp> +#include <mbgl/style/style_layout.hpp> #include <clipper/clipper.hpp> #include <libtess2/tesselator.h> @@ -39,8 +40,7 @@ class FillBucket : public Bucket { typedef ElementGroup<1> line_group_type; public: - FillBucket(std::unique_ptr<const StyleLayoutFill> styleLayout, - FillVertexBuffer &vertexBuffer, + FillBucket(FillVertexBuffer &vertexBuffer, TriangleElementsBuffer &triangleElementsBuffer, LineElementsBuffer &lineElementsBuffer); ~FillBucket() override; @@ -57,7 +57,7 @@ public: void drawVertices(OutlineShader& shader); public: - const std::unique_ptr<const StyleLayoutFill> styleLayout; + StyleLayoutFill layout; private: TESSalloc *allocator; diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp index 6eea0d8d0f..5404398ca0 100644 --- a/src/mbgl/renderer/line_bucket.cpp +++ b/src/mbgl/renderer/line_bucket.cpp @@ -12,22 +12,17 @@ #include <cassert> -struct geometry_too_long_exception : std::exception {}; - using namespace mbgl; -LineBucket::LineBucket(std::unique_ptr<const StyleLayoutLine> styleLayout_, - LineVertexBuffer &vertexBuffer_, +LineBucket::LineBucket(LineVertexBuffer &vertexBuffer_, TriangleElementsBuffer &triangleElementsBuffer_, PointElementsBuffer &pointElementsBuffer_) - : styleLayout(std::move(styleLayout_)), - vertexBuffer(vertexBuffer_), + : vertexBuffer(vertexBuffer_), triangleElementsBuffer(triangleElementsBuffer_), pointElementsBuffer(pointElementsBuffer_), vertex_start(vertexBuffer_.index()), triangle_elements_start(triangleElementsBuffer_.index()), point_elements_start(pointElementsBuffer_.index()) { - assert(styleLayout); } LineBucket::~LineBucket() { @@ -48,7 +43,6 @@ void LineBucket::addGeometry(const GeometryCollection& geometryCollection) { } void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) { - auto &layout = *styleLayout; // TODO: use roundLimit // const float roundLimit = geometry.round_limit; @@ -302,7 +296,7 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) { assert(triangleGroups.back()); triangle_group_type& group = *triangleGroups.back(); - for (const TriangleElement& triangle : triangle_store) { + for (const auto& triangle : triangle_store) { triangleElementsBuffer.add( group.vertex_length + triangle.a, group.vertex_length + triangle.b, @@ -323,7 +317,7 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) { assert(pointGroups.back()); point_group_type& group = *pointGroups.back(); - for (PointElement point : point_store) { + for (const auto point : point_store) { pointElementsBuffer.add(group.vertex_length + point); } diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/line_bucket.hpp index 25b2190176..e6e5f66d57 100644 --- a/src/mbgl/renderer/line_bucket.hpp +++ b/src/mbgl/renderer/line_bucket.hpp @@ -7,6 +7,7 @@ #include <mbgl/geometry/elements_buffer.hpp> #include <mbgl/geometry/line_buffer.hpp> #include <mbgl/style/style_bucket.hpp> +#include <mbgl/style/style_layout.hpp> #include <mbgl/util/vec.hpp> #include <vector> @@ -14,7 +15,6 @@ namespace mbgl { class Style; -class StyleLayoutLine; class LineVertexBuffer; class TriangleElementsBuffer; class LineShader; @@ -27,8 +27,7 @@ class LineBucket : public Bucket { typedef ElementGroup<1> point_group_type; public: - LineBucket(std::unique_ptr<const StyleLayoutLine> styleLayout, - LineVertexBuffer &vertexBuffer, + LineBucket(LineVertexBuffer &vertexBuffer, TriangleElementsBuffer &triangleElementsBuffer, PointElementsBuffer &pointElementsBuffer); ~LineBucket() override; @@ -48,7 +47,7 @@ public: void drawPoints(LinejoinShader& shader); public: - const std::unique_ptr<const StyleLayoutLine> styleLayout; + StyleLayoutLine layout; private: LineVertexBuffer& vertexBuffer; diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index dae9c766cc..0219ccec7f 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -2,7 +2,6 @@ #include <mbgl/platform/log.hpp> #include <mbgl/style/style.hpp> #include <mbgl/style/style_layer.hpp> -#include <mbgl/style/style_layer_group.hpp> #include <mbgl/style/style_bucket.hpp> #include <mbgl/util/std.hpp> #include <mbgl/util/string.hpp> @@ -226,7 +225,7 @@ void Painter::render(const Style& style, const std::set<util::ptr<StyleSource>>& // Update all clipping IDs. ClipIDGenerator generator; - for (const util::ptr<StyleSource> &source : sources) { + for (const auto& source : sources) { generator.update(source->source->getLoadedTiles()); source->source->updateMatrices(projMatrix, state); } @@ -237,23 +236,9 @@ void Painter::render(const Style& style, const std::set<util::ptr<StyleSource>>& // Actually render the layers if (debug::renderTree) { Log::Info(Event::Render, "{"); indent++; } - if (style.layers) { - renderLayers(*style.layers); - } - if (debug::renderTree) { Log::Info(Event::Render, "}"); indent--; } - - // Finalize the rendering, e.g. by calling debug render calls per tile. - // This guarantees that we have at least one function per tile called. - // When only rendering layers via the stylesheet, it's possible that we don't - // ever visit a tile during rendering. - for (const util::ptr<StyleSource> &source : sources) { - source->source->finishRender(*this); - } -} -void Painter::renderLayers(const StyleLayerGroup &group) { // TODO: Correctly compute the number of layers recursively beforehand. - float strata_thickness = 1.0f / (group.layers.size() + 1); + float strata_thickness = 1.0f / (style.layers.size() + 1); // - FIRST PASS ------------------------------------------------------------ // Render everything top-to-bottom by using reverse iterators. Render opaque @@ -263,7 +248,7 @@ void Painter::renderLayers(const StyleLayerGroup &group) { Log::Info(Event::Render, "%*s%s", indent++ * 4, "", "OPAQUE {"); } int i = 0; - for (auto it = group.layers.rbegin(), end = group.layers.rend(); it != end; ++it, ++i) { + for (auto it = style.layers.rbegin(), end = style.layers.rend(); it != end; ++it, ++i) { setOpaque(); setStrata(i * strata_thickness); renderLayer(**it); @@ -279,7 +264,7 @@ void Painter::renderLayers(const StyleLayerGroup &group) { Log::Info(Event::Render, "%*s%s", indent++ * 4, "", "TRANSLUCENT {"); } --i; - for (auto it = group.layers.begin(), end = group.layers.end(); it != end; ++it, --i) { + for (auto it = style.layers.begin(), end = style.layers.end(); it != end; ++it, --i) { setTranslucent(); setStrata(i * strata_thickness); renderLayer(**it); @@ -287,6 +272,16 @@ void Painter::renderLayers(const StyleLayerGroup &group) { if (debug::renderTree) { Log::Info(Event::Render, "%*s%s", --indent * 4, "", "}"); } + + if (debug::renderTree) { Log::Info(Event::Render, "}"); indent--; } + + // Finalize the rendering, e.g. by calling debug render calls per tile. + // This guarantees that we have at least one function per tile called. + // When only rendering layers via the stylesheet, it's possible that we don't + // ever visit a tile during rendering. + for (const auto& source : sources) { + source->source->finishRender(*this); + } } void Painter::renderLayer(const StyleLayer &layer_desc, const Tile::ID* id, const mat4* matrix) { diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index 9c9c6a4642..485098c116 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -43,7 +43,6 @@ class GlyphAtlas; class LineAtlas; class Source; class StyleSource; -class StyleLayerGroup; class FillBucket; class LineBucket; @@ -81,7 +80,6 @@ public: TransformState state, std::chrono::steady_clock::time_point time); - void renderLayers(const StyleLayerGroup &group); void renderLayer(const StyleLayer &layer_desc, const Tile::ID* id = nullptr, const mat4* matrix = nullptr); // Renders a particular layer from a tile. diff --git a/src/mbgl/renderer/painter_clipping.cpp b/src/mbgl/renderer/painter_clipping.cpp index 942be3e9bb..574cbe50af 100644 --- a/src/mbgl/renderer/painter_clipping.cpp +++ b/src/mbgl/renderer/painter_clipping.cpp @@ -17,7 +17,7 @@ void Painter::drawClippingMasks(const std::set<util::ptr<StyleSource>> &sources) coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0)); - for (const util::ptr<StyleSource> &source : sources) { + for (const auto& source : sources) { source->source->drawClippingMasks(*this); } diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp index 2c861aac00..7f9c990776 100644 --- a/src/mbgl/renderer/painter_debug.cpp +++ b/src/mbgl/renderer/painter_debug.cpp @@ -77,7 +77,7 @@ void Painter::renderDebugText(const std::vector<std::string> &strings) { DebugFontBuffer debugFontBuffer; int line = 25; - for (const std::string &str : strings) { + for (const auto& str : strings) { debugFontBuffer.addText(str.c_str(), 10, line, 0.75); line += 20; } diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp index 679e4db7b0..a19d9873af 100644 --- a/src/mbgl/renderer/painter_line.cpp +++ b/src/mbgl/renderer/painter_line.cpp @@ -18,7 +18,7 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const depthMask(false); const auto &properties = layer_desc.getProperties<LineProperties>(); - const auto &layout = *bucket.styleLayout; + const auto &layout = bucket.layout; // the distance over which the line edge fades out. // Retina devices need a smaller distance to avoid aliasing. diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painter_raster.cpp index 5e72676b92..72d15aabd0 100644 --- a/src/mbgl/renderer/painter_raster.cpp +++ b/src/mbgl/renderer/painter_raster.cpp @@ -2,7 +2,6 @@ #include <mbgl/platform/gl.hpp> #include <mbgl/renderer/raster_bucket.hpp> #include <mbgl/style/style_layer.hpp> -#include <mbgl/style/style_layer_group.hpp> #include <mbgl/util/std.hpp> #include <mbgl/map/map.hpp> diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp index 9476146e95..e1b4d88193 100644 --- a/src/mbgl/renderer/painter_symbol.cpp +++ b/src/mbgl/renderer/painter_symbol.cpp @@ -119,7 +119,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c } const auto &properties = layer_desc.getProperties<SymbolProperties>(); - const auto &layout = *bucket.styleLayout; + const auto &layout = bucket.layout; MBGL_CHECK_ERROR(glDisable(GL_STENCIL_TEST)); depthMask(false); diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp index ad54581e10..d5940eccf1 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -22,9 +22,8 @@ namespace mbgl { -SymbolBucket::SymbolBucket(std::unique_ptr<const StyleLayoutSymbol> styleLayout_, Collision &collision_) - : styleLayout(std::move(styleLayout_)), collision(collision_) { - assert(styleLayout); +SymbolBucket::SymbolBucket(Collision &collision_) + : collision(collision_) { } SymbolBucket::~SymbolBucket() { @@ -46,7 +45,6 @@ std::vector<SymbolFeature> SymbolBucket::processFeatures(const GeometryTileLayer const FilterExpression& filter, GlyphStore &glyphStore, const Sprite &sprite) { - auto &layout = *styleLayout; const bool has_text = layout.text.field.size(); const bool has_icon = layout.icon.image.size(); @@ -129,7 +127,6 @@ void SymbolBucket::addFeatures(const GeometryTileLayer& layer, Sprite& sprite, GlyphAtlas& glyphAtlas, GlyphStore& glyphStore) { - auto &layout = *styleLayout; const std::vector<SymbolFeature> features = processFeatures(layer, filter, glyphStore, sprite); float horizontalAlign = 0.5; @@ -175,7 +172,7 @@ void SymbolBucket::addFeatures(const GeometryTileLayer& layer, const auto &fontStack = glyphStore.getFontStack(layout.text.font); - for (const SymbolFeature &feature : features) { + for (const auto& feature : features) { if (!feature.geometry.size()) continue; Shaping shaping; @@ -212,7 +209,7 @@ void SymbolBucket::addFeatures(const GeometryTileLayer& layer, // if either shaping or icon position is present, add the feature if (shaping.size() || image) { - for (const std::vector<Coordinate> &line : feature.geometry) { + for (const auto& line : feature.geometry) { if (line.size()) { addFeature(line, shaping, face, image); } @@ -228,7 +225,6 @@ const PlacementRange fullRange{{2 * M_PI, 0}}; void SymbolBucket::addFeature(const std::vector<Coordinate> &line, const Shaping &shaping, const GlyphPositions &face, const Rect<uint16_t> &image) { assert(line.size()); - auto &layout = *styleLayout; const float minScale = 0.5f; const float glyphSize = 24.0f; @@ -276,7 +272,7 @@ void SymbolBucket::addFeature(const std::vector<Coordinate> &line, const Shaping // TODO: figure out correct ascender height. const vec2<float> origin = {0, -17}; - for (Anchor &anchor : anchors) { + for (auto& anchor : anchors) { // Calculate the scales at which the text and icons can be first shown without overlap Placement glyphPlacement; @@ -363,7 +359,7 @@ void SymbolBucket::addSymbols(Buffer &buffer, const PlacedGlyphs &symbols, float const float placementZoom = std::log(scale) / std::log(2) + zoom; - for (const PlacedGlyph &symbol : symbols) { + for (const auto& symbol : symbols) { const auto &tl = symbol.tl; const auto &tr = symbol.tr; const auto &bl = symbol.bl; diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp index b7291c186c..4f425a49ec 100644 --- a/src/mbgl/renderer/symbol_bucket.hpp +++ b/src/mbgl/renderer/symbol_bucket.hpp @@ -10,7 +10,7 @@ #include <mbgl/text/types.hpp> #include <mbgl/text/glyph.hpp> #include <mbgl/style/style_bucket.hpp> -#include <mbgl/util/ptr.hpp> +#include <mbgl/style/style_layout.hpp> #include <memory> #include <map> @@ -56,7 +56,7 @@ class SymbolBucket : public Bucket { typedef ElementGroup<2> IconElementGroup; public: - SymbolBucket(std::unique_ptr<const StyleLayoutSymbol> styleLayout, Collision &collision); + SymbolBucket(Collision &collision); ~SymbolBucket() override; void render(Painter &painter, const StyleLayer &layer_desc, const Tile::ID &id, @@ -90,7 +90,7 @@ private: void addSymbols(Buffer &buffer, const PlacedGlyphs &symbols, float scale, PlacementRange placementRange); public: - const std::unique_ptr<const StyleLayoutSymbol> styleLayout; + StyleLayoutSymbol layout; bool sdfIcons = false; private: diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index 45217950f6..d0adfe27c2 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -1,6 +1,6 @@ #include <mbgl/style/style.hpp> #include <mbgl/map/sprite.hpp> -#include <mbgl/style/style_layer_group.hpp> +#include <mbgl/style/style_layer.hpp> #include <mbgl/style/style_parser.hpp> #include <mbgl/style/style_bucket.hpp> #include <mbgl/util/constants.hpp> @@ -25,19 +25,21 @@ Style::Style() // for deleting the std::unique_ptr<uv::rwlock>. Style::~Style() {} -void Style::updateProperties(float z, std::chrono::steady_clock::time_point now) { +void Style::cascade(const std::vector<std::string>& classes) { + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + + for (const auto& layer : layers) { + layer->setClasses(classes, now, defaultTransition); + } +} + +void Style::recalculate(float z, std::chrono::steady_clock::time_point now) { uv::writelock lock(mtx); zoomHistory.update(z, now); - if (layers) { - layers->updateProperties(z, now, zoomHistory); - } - - // Apply transitions after the first time. - if (!initial_render_complete) { - initial_render_complete = true; - return; + for (const auto& layer : layers) { + layer->updateProperties(z, now, zoomHistory); } } @@ -49,22 +51,15 @@ void Style::setDefaultTransitionDuration(std::chrono::steady_clock::duration dur defaultTransition.duration = duration; } -void Style::cascadeClasses(const std::vector<std::string>& classes) { - if (layers) { - layers->setClasses(classes, std::chrono::steady_clock::now(), defaultTransition); - } -} - bool Style::hasTransitions() const { - if (layers) { - if (layers->hasTransitions()) { + for (const auto& layer : layers) { + if (layer->hasTransitions()) { return true; } } return false; } - void Style::loadJSON(const uint8_t *const data) { uv::writelock lock(mtx); diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index 4de827a38c..453ebacff5 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -2,54 +2,43 @@ #define MBGL_STYLE_STYLE #include <mbgl/style/property_transition.hpp> -#include <mbgl/style/style_source.hpp> #include <mbgl/style/zoom_history.hpp> #include <mbgl/util/uv.hpp> #include <mbgl/util/ptr.hpp> +#include <mbgl/util/noncopyable.hpp> #include <cstdint> -#include <map> #include <string> -#include <unordered_map> #include <vector> -#include <set> #include <chrono> namespace mbgl { -class Sprite; class StyleLayer; -class StyleLayerGroup; class Style : public util::noncopyable { public: - struct exception : std::runtime_error { exception(const char *msg) : std::runtime_error(msg) {} }; - Style(); ~Style(); void loadJSON(const uint8_t *const data); - size_t layerCount() const; - void updateProperties(float z, std::chrono::steady_clock::time_point now); - - void setDefaultTransitionDuration(std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero()); - void cascadeClasses(const std::vector<std::string>&); + void cascade(const std::vector<std::string>&); + void recalculate(float z, std::chrono::steady_clock::time_point now); + void setDefaultTransitionDuration(std::chrono::steady_clock::duration); bool hasTransitions() const; const std::string &getSpriteURL() const; - util::ptr<StyleLayerGroup> layers; - std::vector<std::string> appliedClasses; + std::vector<util::ptr<StyleLayer>> layers; std::string glyph_url; std::string base; private: std::string sprite_url; PropertyTransition defaultTransition; - bool initial_render_complete = false; std::unique_ptr<uv::rwlock> mtx; ZoomHistory zoomHistory; }; diff --git a/src/mbgl/style/style_layer.cpp b/src/mbgl/style/style_layer.cpp index 1a4354be27..705d9800b1 100644 --- a/src/mbgl/style/style_layer.cpp +++ b/src/mbgl/style/style_layer.cpp @@ -1,6 +1,5 @@ #include <mbgl/style/style_layer.hpp> #include <mbgl/style/style_bucket.hpp> -#include <mbgl/style/style_layer_group.hpp> #include <mbgl/style/property_fallback.hpp> #include <mbgl/util/interpolate.hpp> @@ -32,7 +31,7 @@ void StyleLayer::setClasses(const std::vector<std::string> &class_names, const s // Make sure that we also transition to the fallback value for keys that aren't changed by // any applied classes. - for (std::pair<const PropertyKey, AppliedClassProperties> &property_pair : appliedStyle) { + for (auto& property_pair : appliedStyle) { const PropertyKey key = property_pair.first; if (already_applied.find(key) != already_applied.end()) { // This property has already been set by a previous class, so we don't need to @@ -66,7 +65,7 @@ void StyleLayer::applyClassProperties(const ClassID class_id, // Loop through all the properties in this style, and add transitions to them, if they're // not already the most recent transition. const ClassProperties &class_properties = style_it->second; - for (const std::pair<PropertyKey, PropertyValue> &property_pair : class_properties) { + for (const auto& property_pair : class_properties) { PropertyKey key = property_pair.first; if (already_applied.find(key) != already_applied.end()) { // This property has already been set by a previous class. @@ -126,7 +125,7 @@ void StyleLayer::applyStyleProperty(PropertyKey key, T &target, const float z, c AppliedClassProperties &applied = it->second; // Iterate through all properties that we need to apply in order. const PropertyEvaluator<T> evaluator(z, zoomHistory); - for (AppliedClassProperty &property : applied.properties) { + for (auto& property : applied.properties) { if (now >= property.begin) { // We overwrite the current property with the new value. target = mapbox::util::apply_visitor(evaluator, property.value); @@ -144,7 +143,7 @@ void StyleLayer::applyTransitionedStyleProperty(PropertyKey key, T &target, cons AppliedClassProperties &applied = it->second; // Iterate through all properties that we need to apply in order. const PropertyEvaluator<T> evaluator(z, zoomHistory); - for (AppliedClassProperty &property : applied.properties) { + for (auto& property : applied.properties) { if (now >= property.end) { // We overwrite the current property with the new value. target = mapbox::util::apply_visitor(evaluator, property.value); @@ -250,7 +249,7 @@ void StyleLayer::updateProperties(float z, const std::chrono::steady_clock::time } bool StyleLayer::hasTransitions() const { - for (const std::pair<PropertyKey, AppliedClassProperties> &pair : appliedStyle) { + for (const auto& pair : appliedStyle) { if (pair.second.hasTransitions()) { return true; } diff --git a/src/mbgl/style/style_layer.hpp b/src/mbgl/style/style_layer.hpp index 6e1fc7912b..e33d510975 100644 --- a/src/mbgl/style/style_layer.hpp +++ b/src/mbgl/style/style_layer.hpp @@ -8,6 +8,7 @@ #include <mbgl/style/zoom_history.hpp> #include <mbgl/util/ptr.hpp> +#include <mbgl/util/noncopyable.hpp> #include <vector> #include <string> @@ -18,9 +19,8 @@ namespace mbgl { class StyleBucket; -class StyleLayerGroup; -class StyleLayer { +class StyleLayer : public util::noncopyable { public: StyleLayer(const std::string &id, std::map<ClassID, ClassProperties> &&styles); diff --git a/src/mbgl/style/style_layer_group.cpp b/src/mbgl/style/style_layer_group.cpp deleted file mode 100644 index f57ec5cc7b..0000000000 --- a/src/mbgl/style/style_layer_group.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include <mbgl/style/style_layer_group.hpp> - -namespace mbgl { - -void StyleLayerGroup::setClasses(const std::vector<std::string> &class_names, std::chrono::steady_clock::time_point now, - const PropertyTransition &defaultTransition) { - for (const util::ptr<StyleLayer> &layer : layers) { - if (layer) { - layer->setClasses(class_names, now, defaultTransition); - } - } -} - -void StyleLayerGroup::updateProperties(float z, std::chrono::steady_clock::time_point now, ZoomHistory &zoomHistory) { - for (const util::ptr<StyleLayer> &layer: layers) { - if (layer) { - layer->updateProperties(z, now, zoomHistory); - } - } -} - -bool StyleLayerGroup::hasTransitions() const { - for (const util::ptr<const StyleLayer> &layer: layers) { - if (layer) { - if (layer->hasTransitions()) { - return true; - } - } - } - return false; -} - - -} diff --git a/src/mbgl/style/style_layer_group.hpp b/src/mbgl/style/style_layer_group.hpp deleted file mode 100644 index 79b75a55e9..0000000000 --- a/src/mbgl/style/style_layer_group.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef MBGL_STYLE_STYLE_LAYER_GROUP -#define MBGL_STYLE_STYLE_LAYER_GROUP - -#include <mbgl/style/style_layer.hpp> - -#include <vector> -#include <chrono> - -namespace mbgl { - -class StyleLayerGroup { -public: - void setClasses(const std::vector<std::string> &class_names, std::chrono::steady_clock::time_point now, - const PropertyTransition &defaultTransition); - void updateProperties(float z, std::chrono::steady_clock::time_point now, ZoomHistory &zoomHistory); - - bool hasTransitions() const; -public: - std::vector<util::ptr<StyleLayer>> layers; -}; - -} - -#endif diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp index 66938987fb..7024853704 100644 --- a/src/mbgl/style/style_parser.cpp +++ b/src/mbgl/style/style_parser.cpp @@ -1,6 +1,6 @@ #include <mbgl/style/style_source.hpp> #include <mbgl/style/style_parser.hpp> -#include <mbgl/style/style_layer_group.hpp> +#include <mbgl/style/style_layer.hpp> #include <mbgl/map/annotation.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/std.hpp> @@ -9,6 +9,13 @@ #include <mbgl/platform/log.hpp> #include <csscolorparser/csscolorparser.hpp> +#pragma GCC diagnostic push +#ifndef __clang__ +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#endif +#include <boost/algorithm/string.hpp> +#pragma GCC diagnostic pop + #include <algorithm> namespace mbgl { @@ -28,8 +35,7 @@ void StyleParser::parse(JSVal document) { } if (document.HasMember("layers")) { - root = createLayers(document["layers"]); - parseLayers(); + parseLayers(document["layers"]); // create point annotations layer // @@ -38,8 +44,8 @@ void StyleParser::parse(JSVal document) { std::map<ClassID, ClassProperties> paints; util::ptr<StyleLayer> annotations = std::make_shared<StyleLayer>(id, std::move(paints)); annotations->type = StyleLayerType::Symbol; - layers.emplace(id, std::pair<JSVal, util::ptr<StyleLayer>> { JSVal(id), annotations }); - root->layers.emplace_back(annotations); + layersMap.emplace(id, std::pair<JSVal, util::ptr<StyleLayer>> { JSVal(id), annotations }); + layers.emplace_back(annotations); util::ptr<StyleBucket> pointBucket = std::make_shared<StyleBucket>(annotations->type); pointBucket->name = annotations->id; @@ -447,6 +453,13 @@ bool StyleParser::parseOptionalProperty(const char *property_name, PropertyKey k } } +std::string normalizeFontStack(const std::string &name) { + namespace algo = boost::algorithm; + std::vector<std::string> parts; + algo::split(parts, name, algo::is_any_of(","), algo::token_compress_on); + std::for_each(parts.begin(), parts.end(), [](std::string& str) { algo::trim(str); }); + return algo::join(parts, ", "); +} template<> std::tuple<bool, std::string> StyleParser::parseProperty(JSVal value, const char *property_name) { if (!value.IsString()) { @@ -454,7 +467,13 @@ template<> std::tuple<bool, std::string> StyleParser::parseProperty(JSVal value, return std::tuple<bool, std::string> { false, std::string() }; } - return std::tuple<bool, std::string> { true, { value.GetString(), value.GetStringLength() } }; + if (std::string { "text-font" } == property_name) { + return std::tuple<bool, std::string> { + true, normalizeFontStack({ value.GetString(), value.GetStringLength() }) + }; + } else { + return std::tuple<bool, std::string> { true, { value.GetString(), value.GetStringLength() } }; + } } template<> std::tuple<bool, bool> StyleParser::parseProperty(JSVal value, const char *property_name) { @@ -662,61 +681,48 @@ template<> std::tuple<bool, PiecewiseConstantFunction<Faded<std::string>>> Style #pragma mark - Parse Layers -std::unique_ptr<StyleLayerGroup> StyleParser::createLayers(JSVal value) { - if (value.IsArray()) { - std::unique_ptr<StyleLayerGroup> group = util::make_unique<StyleLayerGroup>(); - for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { - util::ptr<StyleLayer> layer = createLayer(value[i]); - if (layer) { - group->layers.emplace_back(layer); - } - } - return group; - } else { +void StyleParser::parseLayers(JSVal value) { + if (!value.IsArray()) { Log::Warning(Event::ParseStyle, "layers must be an array"); - return nullptr; + return; } -} -util::ptr<StyleLayer> StyleParser::createLayer(JSVal value) { - if (value.IsObject()) { - if (!value.HasMember("id")) { + for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { + JSVal layerValue = value[i]; + + if (!layerValue.IsObject()) { + Log::Warning(Event::ParseStyle, "layer must be an object"); + continue; + } + + if (!layerValue.HasMember("id")) { Log::Warning(Event::ParseStyle, "layer must have an id"); - return nullptr; + continue; } - JSVal id = value["id"]; + JSVal id = layerValue["id"]; if (!id.IsString()) { Log::Warning(Event::ParseStyle, "layer id must be a string"); - return nullptr; + continue; } - const std::string layer_id = { id.GetString(), id.GetStringLength() }; - - if (layers.find(layer_id) != layers.end()) { - Log::Warning(Event::ParseStyle, "duplicate layer id %s", layer_id.c_str()); - return nullptr; + const std::string layerID = { id.GetString(), id.GetStringLength() }; + if (layersMap.find(layerID) != layersMap.end()) { + Log::Warning(Event::ParseStyle, "duplicate layer id %s", layerID.c_str()); + continue; } // Parse paints already, as they can't be inherited anyway. std::map<ClassID, ClassProperties> paints; - parsePaints(value, paints); - - util::ptr<StyleLayer> layer = std::make_shared<StyleLayer>( - layer_id, std::move(paints)); + parsePaints(layerValue, paints); - // Store the layer ID so we can reference it later. - layers.emplace(layer_id, std::pair<JSVal, util::ptr<StyleLayer>> { value, layer }); + util::ptr<StyleLayer> layer = std::make_shared<StyleLayer>(layerID, std::move(paints)); - return layer; - } else { - Log::Warning(Event::ParseStyle, "layer must be an object"); - return nullptr; + layers.emplace_back(layer); + layersMap.emplace(layerID, std::pair<JSVal, util::ptr<StyleLayer>> { layerValue, layer }); } -} -void StyleParser::parseLayers() { - for (std::pair<const std::string, std::pair<JSVal, util::ptr<StyleLayer>>> &pair : layers) { + for (auto& pair : layersMap) { parseLayer(pair.second); } } @@ -904,8 +910,8 @@ void StyleParser::parseReference(JSVal value, util::ptr<StyleLayer> &layer) { return; } const std::string ref { value.GetString(), value.GetStringLength() }; - auto it = layers.find(ref); - if (it == layers.end()) { + auto it = layersMap.find(ref); + if (it == layersMap.end()) { Log::Warning(Event::ParseStyle, "layer '%s' references unknown layer %s", layer->id.c_str(), ref.c_str()); // We cannot parse this layer further. return; diff --git a/src/mbgl/style/style_parser.hpp b/src/mbgl/style/style_parser.hpp index 736cb9e9fa..9ef74c8dc1 100644 --- a/src/mbgl/style/style_parser.hpp +++ b/src/mbgl/style/style_parser.hpp @@ -17,7 +17,6 @@ namespace mbgl { enum class ClassID : uint32_t; class StyleLayer; -class StyleLayerGroup; class StyleParser { public: @@ -27,8 +26,8 @@ public: void parse(JSVal document); - util::ptr<StyleLayerGroup> getLayers() { - return root; + std::vector<util::ptr<StyleLayer>> getLayers() { + return layers; } std::string getSprite() const { @@ -44,10 +43,7 @@ private: JSVal replaceConstant(JSVal value); void parseSources(JSVal value); - - std::unique_ptr<StyleLayerGroup> createLayers(JSVal value); - util::ptr<StyleLayer> createLayer(JSVal value); - void parseLayers(); + void parseLayers(JSVal value); void parseLayer(std::pair<JSVal, util::ptr<StyleLayer>> &pair); void parsePaints(JSVal value, std::map<ClassID, ClassProperties> &paints); void parsePaint(JSVal, ClassProperties &properties); @@ -97,10 +93,10 @@ private: std::unordered_map<std::string, const util::ptr<StyleSource>> sources; // This stores the root layer. - util::ptr<StyleLayerGroup> root; + std::vector<util::ptr<StyleLayer>> layers; // This maps ids to Layer objects, with all items being at the root level. - std::unordered_map<std::string, std::pair<JSVal, util::ptr<StyleLayer>>> layers; + std::unordered_map<std::string, std::pair<JSVal, util::ptr<StyleLayer>>> layersMap; // Store a stack of layers we're parsing right now. This is to prevent reference cycles. std::forward_list<StyleLayer *> stack; diff --git a/src/mbgl/text/collision.cpp b/src/mbgl/text/collision.cpp index 2e0ec6dce2..422cd0a60a 100644 --- a/src/mbgl/text/collision.cpp +++ b/src/mbgl/text/collision.cpp @@ -91,7 +91,7 @@ GlyphBox getMergedGlyphs(const GlyphBoxes &boxes, const CollisionAnchor &anchor) mergedGlyphs.anchor = anchor; CollisionRect &box = mergedGlyphs.box; - for (const GlyphBox &glyph : boxes) { + for (const auto& glyph : boxes) { const CollisionRect &gbox = glyph.box; box.tl.x = util::min(box.tl.x, gbox.tl.x); box.tl.y = util::min(box.tl.y, gbox.tl.y); @@ -105,7 +105,7 @@ GlyphBox getMergedGlyphs(const GlyphBoxes &boxes, const CollisionAnchor &anchor) float Collision::getPlacementScale(const GlyphBoxes &glyphs, float minPlacementScale, bool avoidEdges) { - for (const GlyphBox &glyph : glyphs) { + for (const auto& glyph : glyphs) { const CollisionRect &box = glyph.box; const CollisionRect &bbox = glyph.hBox ? glyph.hBox.get() : glyph.box; const CollisionAnchor &anchor = glyph.anchor; @@ -141,7 +141,7 @@ float Collision::getPlacementScale(const GlyphBoxes &glyphs, float minPlacementS const CollisionAnchor &na = anchor; // new anchor const CollisionRect &nb = box; // new box - for (const PlacementValue &value : blocking) { + for (const auto& value : blocking) { const PlacementBox &placement = std::get<1>(value); const CollisionAnchor &oa = placement.anchor; // old anchor const CollisionRect &ob = placement.box; // old box @@ -198,7 +198,7 @@ PlacementRange Collision::getPlacementRange(const GlyphBoxes &glyphs, float plac bool horizontal) { PlacementRange placementRange = {{2.0f * M_PI, 0}}; - for (const GlyphBox &glyph : glyphs) { + for (const auto& glyph : glyphs) { const CollisionRect &bbox = glyph.hBox ? glyph.hBox.get() : glyph.box; const CollisionAnchor &anchor = glyph.anchor; @@ -216,7 +216,7 @@ PlacementRange Collision::getPlacementRange(const GlyphBoxes &glyphs, float plac cTree.query(bgi::intersects(query_box), std::back_inserter(blocking)); } - for (const PlacementValue &value : blocking) { + for (const auto& value : blocking) { const Box &s = std::get<0>(value); const PlacementBox &b = std::get<1>(value); const CollisionRect &bbox2 = b.hBox ? b.hBox.get() : b.box; @@ -265,7 +265,7 @@ void Collision::insert(const GlyphBoxes &glyphs, const CollisionAnchor &anchor, std::vector<PlacementValue> allBounds; allBounds.reserve(glyphs.size()); - for (const GlyphBox &glyph : glyphs) { + for (const auto& glyph : glyphs) { const CollisionRect &box = glyph.box; const CollisionRect &bbox = glyph.hBox ? glyph.hBox.get() : glyph.box; diff --git a/src/mbgl/text/collision.hpp b/src/mbgl/text/collision.hpp index b009982997..bba07b0fb1 100644 --- a/src/mbgl/text/collision.hpp +++ b/src/mbgl/text/collision.hpp @@ -4,6 +4,7 @@ #include <mbgl/text/types.hpp> #pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wshadow" diff --git a/src/mbgl/text/glyph_store.cpp b/src/mbgl/text/glyph_store.cpp index ab1776c04b..fd8f99ea5b 100644 --- a/src/mbgl/text/glyph_store.cpp +++ b/src/mbgl/text/glyph_store.cpp @@ -68,7 +68,7 @@ void align(Shaping &shaping, const float justify, const float horizontalAlign, const float shiftX = (justify - horizontalAlign) * maxLineLength; const float shiftY = (-verticalAlign * (line + 1) + 0.5) * lineHeight; - for (PositionedGlyph &glyph : shaping) { + for (auto& glyph : shaping) { glyph.x += shiftX; glyph.y += shiftY; } @@ -251,7 +251,7 @@ void GlyphStore::waitForGlyphRanges(const std::string &fontStack, const std::set // Attempt to load the glyph range. If the GlyphSet already exists, we are getting back // the same shared_future. - for (GlyphRange range : glyphRanges) { + for (const auto range : glyphRanges) { futures.emplace_back(loadGlyphRange(fontStack, rangeSets, range)); } } @@ -259,7 +259,7 @@ void GlyphStore::waitForGlyphRanges(const std::string &fontStack, const std::set // Now that we potentially created all GlyphSets, we are waiting for the results, one by one. // When we get a result (or the GlyphSet is aready loaded), we are attempting to parse the // GlyphSet. - for (std::shared_future<GlyphPBF &> &future : futures) { + for (const auto& future : futures) { future.get().parse(stack); } } diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 9d9e82c75c..6a142cdf65 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -110,7 +110,7 @@ GlyphBox getMergedBoxes(const GlyphBoxes &glyphs, const Anchor &anchor) { CollisionRect &box = mergedglyphs.box; - for (const GlyphBox &glyph : glyphs) { + for (const auto& glyph : glyphs) { const CollisionRect &gbox = glyph.box; box.tl.x = util::min(box.tl.x, gbox.tl.x); box.tl.y = util::min(box.tl.y, gbox.tl.y); @@ -211,7 +211,7 @@ Placement Placement::getGlyphs(Anchor &anchor, const vec2<float> &origin, const const uint32_t buffer = 3; - for (const PositionedGlyph &shape : shaping) { + for (const auto& shape : shaping) { auto face_it = face.find(shape.glyph); if (face_it == face.end()) continue; @@ -250,7 +250,7 @@ Placement Placement::getGlyphs(Anchor &anchor, const vec2<float> &origin, const const CollisionRect obox{boxScale * x1, boxScale * y1, boxScale * x2, boxScale * y2}; - for (const GlyphInstance &instance : glyphInstances) { + for (const auto& instance : glyphInstances) { vec2<float> tl = otl; vec2<float> tr = otr; vec2<float> bl = obl; @@ -301,7 +301,7 @@ Placement Placement::getGlyphs(Anchor &anchor, const vec2<float> &origin, const const float minPlacementScale = anchor.scale; placement.minScale = std::numeric_limits<float>::infinity(); - for (const GlyphBox &box : placement.boxes) { + for (const auto& box : placement.boxes) { placement.minScale = util::min(placement.minScale, box.minScale); } placement.minScale = util::max(minPlacementScale, Placement::globalMinScale); diff --git a/src/mbgl/text/rotation_range.cpp b/src/mbgl/text/rotation_range.cpp index 664ea9c709..efaa1c67ed 100644 --- a/src/mbgl/text/rotation_range.cpp +++ b/src/mbgl/text/rotation_range.cpp @@ -17,7 +17,7 @@ CollisionRange mergeCollisions(const CollisionList &collisions, float min = 2.0f * M_PI; float max = 0.0f; - for (CollisionRange collision : collisions) { + for (const auto& collision : collisions) { bool entryOutside = ignoreRange[0] <= collision[0] && collision[0] <= ignoreRange[1]; bool exitOutside = diff --git a/src/mbgl/util/clip_ids.cpp b/src/mbgl/util/clip_ids.cpp index 8b1dcf8dd0..e7833b679f 100644 --- a/src/mbgl/util/clip_ids.cpp +++ b/src/mbgl/util/clip_ids.cpp @@ -18,7 +18,7 @@ ClipIDGenerator::Leaf::Leaf(Tile &tile_) : tile(tile_) {} void ClipIDGenerator::Leaf::add(const Tile::ID &p) { if (p.isChildOf(tile.id)) { // Ensure that no already present child is a parent of the new p. - for (const Tile::ID &child : children) { + for (const auto& child : children) { if (p.isChildOf(child)) return; } @@ -31,7 +31,7 @@ bool ClipIDGenerator::Leaf::operator==(const Leaf &other) const { } bool ClipIDGenerator::reuseExisting(Leaf &leaf) { - for (const std::vector<Leaf> &pool : pools) { + for (const auto& pool : pools) { auto existing = std::find(pool.begin(), pool.end(), leaf); if (existing != pool.end()) { leaf.tile.clip = existing->tile.clip; @@ -80,7 +80,7 @@ void ClipIDGenerator::update(std::forward_list<Tile *> tiles) { // We are starting our count with 1 since we need at least 1 bit set to distinguish between // areas without any tiles whatsoever and the current area. uint8_t count = 1; - for (Leaf &leaf : pool) { + for (auto& leaf : pool) { leaf.tile.clip.mask = mask; leaf.tile.clip.reference = count++ << bit_offset; } diff --git a/src/mbgl/util/mapbox.cpp b/src/mbgl/util/mapbox.cpp index 5d9c630c11..a8da81d1fd 100644 --- a/src/mbgl/util/mapbox.cpp +++ b/src/mbgl/util/mapbox.cpp @@ -8,11 +8,12 @@ namespace mapbox { const std::string mapbox = "mapbox://"; -std::string normalizeURL(const std::string& url, const std::string& accessToken) { +std::string normalizeURL(const std::string& url, const std::string& pathPrefix, const std::string& accessToken) { if (accessToken.empty()) throw std::runtime_error("You must provide a Mapbox API access token for Mapbox tile sources"); - return std::string("https://api.tiles.mapbox.com/v4/") + return std::string("https://api.tiles.mapbox.com") + + pathPrefix + url.substr(mapbox.length()) + "?access_token=" + accessToken; @@ -22,7 +23,7 @@ std::string normalizeSourceURL(const std::string& url, const std::string& access if (url.compare(0, mapbox.length(), mapbox) != 0) return url; - std::string result = normalizeURL(url + ".json", accessToken); + std::string result = normalizeURL(url + ".json", "/v4/", accessToken); // TileJSON requests need a secure flag appended to their URLs so // that the server knows to send SSL-ified resource references. @@ -31,11 +32,20 @@ std::string normalizeSourceURL(const std::string& url, const std::string& access return result; } +std::string normalizeStyleURL(const std::string& url, const std::string& accessToken) { + if (url.compare(0, mapbox.length(), mapbox) != 0) + return url; + + const std::string user = url.substr(mapbox.length(), url.find('.') - mapbox.length()); + + return normalizeURL(url, "/styles/v1/" + user + "/", accessToken); +} + std::string normalizeGlyphsURL(const std::string& url, const std::string& accessToken) { if (url.compare(0, mapbox.length(), mapbox) != 0) return url; - return normalizeURL(url, accessToken); + return normalizeURL(url, "/v4/", accessToken); } std::string normalizeTileURL(const std::string& url, const std::string& sourceURL, SourceType sourceType) { diff --git a/src/mbgl/util/mapbox.hpp b/src/mbgl/util/mapbox.hpp index 8ad92c0b40..86ea349b8c 100644 --- a/src/mbgl/util/mapbox.hpp +++ b/src/mbgl/util/mapbox.hpp @@ -9,6 +9,7 @@ namespace util { namespace mapbox { std::string normalizeSourceURL(const std::string& url, const std::string& accessToken); +std::string normalizeStyleURL(const std::string& url, const std::string& accessToken); std::string normalizeGlyphsURL(const std::string& url, const std::string& accessToken); std::string normalizeTileURL(const std::string& url, const std::string& sourceURL, SourceType sourceType); diff --git a/src/mbgl/util/merge_lines.cpp b/src/mbgl/util/merge_lines.cpp index 7eb8306707..4ff1caaf76 100644 --- a/src/mbgl/util/merge_lines.cpp +++ b/src/mbgl/util/merge_lines.cpp @@ -1,13 +1,16 @@ #include "merge_lines.hpp" -#include <sstream> + +#include <boost/functional/hash.hpp> namespace mbgl { namespace util { +using Index = std::map<size_t, unsigned int>; + unsigned int mergeFromRight(std::vector<SymbolFeature> &features, - std::map<std::string, unsigned int> &rightIndex, - std::map<std::string, unsigned int>::iterator left, - std::string &rightKey, + Index &rightIndex, + Index::iterator left, + size_t rightKey, std::vector<std::vector<Coordinate>> &geom) { unsigned int index = left->second; @@ -21,9 +24,9 @@ unsigned int mergeFromRight(std::vector<SymbolFeature> &features, } unsigned int mergeFromLeft(std::vector<SymbolFeature> &features, - std::map<std::string, unsigned int> &leftIndex, - std::string &leftKey, - std::map<std::string, unsigned int>::iterator right, + Index &leftIndex, + size_t leftKey, + Index::iterator right, std::vector<std::vector<Coordinate>> &geom) { unsigned int index = right->second; @@ -37,21 +40,20 @@ unsigned int mergeFromLeft(std::vector<SymbolFeature> &features, return index; } -std::string -getKey(const std::u32string &text, const std::vector<std::vector<Coordinate>> &geom, bool onRight) { - const Coordinate &coord = onRight ? geom[0].back() : geom[0].front(); - std::ostringstream key; - for (const char32_t &c : text) { - key << (char)c; - } - key << ":" << coord.x << ":" << coord.y; - return key.str(); +size_t +getKey(const std::u32string& text, const std::vector<std::vector<Coordinate>>& geom, bool onRight) { + const Coordinate& coord = onRight ? geom[0].back() : geom[0].front(); + + auto hash = std::hash<std::u32string>()(text); + boost::hash_combine(hash, coord.x); + boost::hash_combine(hash, coord.y); + return hash; } void mergeLines(std::vector<SymbolFeature> &features) { - std::map<std::string, unsigned int> leftIndex; - std::map<std::string, unsigned int> rightIndex; + Index leftIndex; + Index rightIndex; for (unsigned int k = 0; k < features.size(); k++) { SymbolFeature &feature = features[k]; @@ -61,11 +63,11 @@ void mergeLines(std::vector<SymbolFeature> &features) { continue; } - std::string leftKey = getKey(feature.label, geometry, false); - std::string rightKey = getKey(feature.label, geometry, true); + const auto leftKey = getKey(feature.label, geometry, false); + const auto rightKey = getKey(feature.label, geometry, true); - auto left = rightIndex.find(leftKey); - auto right = leftIndex.find(rightKey); + const auto left = rightIndex.find(leftKey); + const auto right = leftIndex.find(rightKey); if ((left != rightIndex.end()) && (right != leftIndex.end()) && (left->second != right->second)) { diff --git a/src/mbgl/util/scaling.cpp b/src/mbgl/util/scaling.cpp index a554b2e137..efc2709df3 100644 --- a/src/mbgl/util/scaling.cpp +++ b/src/mbgl/util/scaling.cpp @@ -49,38 +49,39 @@ namespace util { void bilinearScale(const uint32_t* srcData, const vec2<uint32_t>& srcSize, const Rect<uint32_t>& srcPos, uint32_t* dstData, const vec2<uint32_t>& dstSize, - const Rect<uint32_t>& dstPos) { + const Rect<uint32_t>& dstPos, bool wrap) { const auto factor = getFactor(srcPos, dstPos); const auto bounds = getBounds(srcSize, srcPos, dstSize, dstPos, factor); - double fractSrcY = srcPos.y; - double fractSrcX; uint32_t x, y; size_t i = dstSize.x * dstPos.y + dstPos.x; for (y = 0; y < bounds.y; y++) { - fractSrcX = srcPos.x; - const uint32_t srcY0 = fractSrcY; - const uint32_t srcY1 = std::min(srcY0 + 1, srcSize.y - 1); + const double fractY = y * factor.y; + const uint32_t Y0 = fractY; + const uint32_t Y1 = wrap ? (Y0 + 1) % srcPos.h : (Y0 + 1); + const uint32_t srcY0 = srcPos.y + Y0; + const uint32_t srcY1 = std::min(srcPos.y + Y1, srcSize.y - 1); for (x = 0; x < bounds.x; x++) { - const uint32_t srcX0 = fractSrcX; - const uint32_t srcX1 = std::min(srcX0 + 1, srcSize.x - 1); + const double fractX = x * factor.x; + const uint32_t X0 = fractX; + const uint32_t X1 = wrap ? (X0 + 1) % srcPos.w : (X0 + 1); + const uint32_t srcX0 = srcPos.x + X0; + const uint32_t srcX1 = std::min(srcPos.x + X1, srcSize.x - 1); const uint32_t tl = srcData[srcSize.x * srcY0 + srcX0]; const uint32_t tr = srcData[srcSize.x * srcY0 + srcX1]; const uint32_t bl = srcData[srcSize.x * srcY1 + srcX0]; const uint32_t br = srcData[srcSize.x * srcY1 + srcX1]; - const double dx = fractSrcX - srcX0; - const double dy = fractSrcY - srcY0; + const double dx = fractX - X0; + const double dy = fractY - Y0; uint32_t& dst = dstData[i + x]; b<0>(dst) = bilinearInterpolate(b<0>(tl), b<0>(tr), b<0>(bl), b<0>(br), dx, dy); b<1>(dst) = bilinearInterpolate(b<1>(tl), b<1>(tr), b<1>(bl), b<1>(br), dx, dy); b<2>(dst) = bilinearInterpolate(b<2>(tl), b<2>(tr), b<2>(bl), b<2>(br), dx, dy); b<3>(dst) = bilinearInterpolate(b<3>(tl), b<3>(tr), b<3>(bl), b<3>(br), dx, dy); - fractSrcX += factor.x; } i += dstSize.x; - fractSrcY += factor.y; } } @@ -108,4 +109,4 @@ void nearestNeighborScale(const uint32_t* srcData, const vec2<uint32_t>& srcSize } } -}
\ No newline at end of file +} diff --git a/src/mbgl/util/scaling.hpp b/src/mbgl/util/scaling.hpp index d2625e9219..74a43eb621 100644 --- a/src/mbgl/util/scaling.hpp +++ b/src/mbgl/util/scaling.hpp @@ -12,7 +12,7 @@ namespace util { void bilinearScale(const uint32_t* srcData, const vec2<uint32_t>& srcSize, const Rect<uint32_t>& srcPos, uint32_t* dstData, const vec2<uint32_t>& dstSize, - const Rect<uint32_t>& dstPos); + const Rect<uint32_t>& dstPos, bool wrap); void nearestNeighborScale(const uint32_t* srcData, const vec2<uint32_t>& srcSize, const Rect<uint32_t>& srcPos, uint32_t* dstData, |