diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2014-07-31 18:14:26 +0200 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2014-07-31 18:14:26 +0200 |
commit | 75c079adb16a24cbd8b8111993a67313fd52718a (patch) | |
tree | 400207782ad718fa605414a6132dcfa20a09415d | |
parent | fa3a41136ca6345f34b53a1f211926cc1bd8649c (diff) | |
download | qtlocation-mapboxgl-75c079adb16a24cbd8b8111993a67313fd52718a.tar.gz |
move sprite to a use future loading
-rw-r--r-- | include/mbgl/geometry/sprite_atlas.hpp | 17 | ||||
-rw-r--r-- | include/mbgl/map/map.hpp | 5 | ||||
-rw-r--r-- | include/mbgl/map/sprite.hpp | 32 | ||||
-rw-r--r-- | include/mbgl/map/tile_parser.hpp | 5 | ||||
-rw-r--r-- | include/mbgl/renderer/symbol_bucket.hpp | 5 | ||||
-rw-r--r-- | include/mbgl/style/style.hpp | 6 | ||||
-rw-r--r-- | src/geometry/sprite_atlas.cpp | 65 | ||||
-rw-r--r-- | src/map/map.cpp | 27 | ||||
-rw-r--r-- | src/map/sprite.cpp | 100 | ||||
-rw-r--r-- | src/map/tile_parser.cpp | 6 | ||||
-rw-r--r-- | src/map/vector_tile_data.cpp | 2 | ||||
-rw-r--r-- | src/renderer/painter_fill.cpp | 4 | ||||
-rw-r--r-- | src/renderer/symbol_bucket.cpp | 5 | ||||
-rw-r--r-- | src/style/style.cpp | 5 |
14 files changed, 141 insertions, 143 deletions
diff --git a/include/mbgl/geometry/sprite_atlas.hpp b/include/mbgl/geometry/sprite_atlas.hpp index 4b55540cc8..dc2378c2fb 100644 --- a/include/mbgl/geometry/sprite_atlas.hpp +++ b/include/mbgl/geometry/sprite_atlas.hpp @@ -26,18 +26,21 @@ public: // Changes the pixel ratio. bool resize(float newRatio); - // Update uninitialized sprites in this atlas from the given sprite. + // Update uninitialized (= outdated) sprites in this atlas from the given sprite. void update(const Sprite &sprite); - // Returns the coordinates of a square icon. The getter also *creates* new square icons in the - // atlas if they don't exist, but they'll be default-initialized with a a black circle. - Rect<dimension> getIcon(int size, const std::string &name); - // Returns the coordinates of an image that is sourced from the sprite image. - // This getter does not create images, as the dimension of the texture us unknown if the - // sprite is not yet loaded. Instead, it returns a 0/0/0/0 rect. + // This getter attempts to read the image from the sprite if it is already loaded. + // In that case, it copies it into the sprite atlas and returns the dimensions. + // Otherwise, it returns a 0/0/0/0 rect. Rect<dimension> getImage(const std::string &name, const Sprite &sprite); + // Returns the coordinates of an image that is sourced from the sprite image. + // This getter waits until the sprite image was loaded, copies it into the sprite + // image and returns the dimensions. + // NEVER CALL THIS FUNCTION FROM THE RENDER THREAD! it is blocking. + Rect<dimension> waitForImage(const std::string &name, const Sprite &sprite); + // Binds the image buffer of this sprite atlas to the GPU, and uploads data if it is out // of date. void bind(bool linear = false); diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 81d55b217f..0a94fc7ed2 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -21,6 +21,7 @@ class GlyphAtlas; class GlyphStore; class LayerDescription; class SpriteAtlas; +class Sprite; class Style; class StyleLayer; class StyleLayerGroup; @@ -110,10 +111,11 @@ public: public: inline const TransformState &getState() const { return state; } - inline std::shared_ptr<const Style> getStyle() const { return style; } + inline std::shared_ptr<Style> getStyle() const { return style; } inline std::shared_ptr<GlyphAtlas> getGlyphAtlas() { return glyphAtlas; } inline std::shared_ptr<GlyphStore> getGlyphStore() { return glyphStore; } inline std::shared_ptr<SpriteAtlas> getSpriteAtlas() { return spriteAtlas; } + std::shared_ptr<Sprite> getSprite(); inline std::shared_ptr<Texturepool> getTexturepool() { return texturepool; } inline std::shared_ptr<uv::loop> getLoop() { return loop; } inline timestamp getAnimationTime() const { return animationTime; } @@ -172,6 +174,7 @@ private: std::shared_ptr<GlyphAtlas> glyphAtlas; std::shared_ptr<GlyphStore> glyphStore; std::shared_ptr<SpriteAtlas> spriteAtlas; + std::shared_ptr<Sprite> sprite; std::shared_ptr<Texturepool> texturepool; Painter painter; diff --git a/include/mbgl/map/sprite.hpp b/include/mbgl/map/sprite.hpp index 3f8d5611a4..40d37d5da1 100644 --- a/include/mbgl/map/sprite.hpp +++ b/include/mbgl/map/sprite.hpp @@ -2,6 +2,7 @@ #define MBGL_STYLE_SPRITE #include <mbgl/util/image.hpp> +#include <mbgl/util/noncopyable.hpp> #include <cstdint> #include <atomic> @@ -9,6 +10,7 @@ #include <memory> #include <string> #include <unordered_map> +#include <future> namespace mbgl { @@ -28,37 +30,43 @@ public: uint8_t pixelRatio = 1; }; -class Sprite : public std::enable_shared_from_this<Sprite> { -public: - Sprite(Map &map, float pixelRatio = 1); +class Sprite : public std::enable_shared_from_this<Sprite>, private util::noncopyable { +private: + struct Key {}; + void load(); - void load(const std::string& base_url); +public: + Sprite(const Key &, const std::string& base_url, float pixelRatio); + static std::shared_ptr<Sprite> Create(const std::string& base_url, float pixelRatio); const SpritePosition &getSpritePosition(const std::string& name) const; + void waitUntilLoaded() const; bool isLoaded() const; + operator bool() const; + public: const float pixelRatio; + const std::string url; std::unique_ptr<util::Image> raster; private: - void asyncParseJSON(); - void asyncParseImage(); - - static void parseJSON(std::shared_ptr<Sprite> &sprite); - static void parseImage(std::shared_ptr<Sprite> &sprite); - static void complete(std::shared_ptr<Sprite> &sprite); + void parseJSON(); + void parseImage(); + void complete(); private: - Map ↦ - std::string url; std::string body; std::string image; std::atomic<bool> loadedImage; std::atomic<bool> loadedJSON; std::unordered_map<std::string, SpritePosition> pos; const SpritePosition empty; + + std::promise<void> promise; + std::future<void> future; + }; } diff --git a/include/mbgl/map/tile_parser.hpp b/include/mbgl/map/tile_parser.hpp index 84505c1e05..b407502434 100644 --- a/include/mbgl/map/tile_parser.hpp +++ b/include/mbgl/map/tile_parser.hpp @@ -18,6 +18,7 @@ class FontStack; class GlyphAtlas; class GlyphStore; class SpriteAtlas; +class Sprite; class Style; class StyleBucket; class StyleBucketFill; @@ -32,7 +33,8 @@ public: const std::shared_ptr<const Style> &style, const std::shared_ptr<GlyphAtlas> &glyphAtlas, const std::shared_ptr<GlyphStore> &glyphStore, - const std::shared_ptr<SpriteAtlas> &spriteAtlas); + const std::shared_ptr<SpriteAtlas> &spriteAtlas, + const std::shared_ptr<Sprite> &sprite); public: void parse(); @@ -57,6 +59,7 @@ private: std::shared_ptr<GlyphAtlas> glyphAtlas; std::shared_ptr<GlyphStore> glyphStore; std::shared_ptr<SpriteAtlas> spriteAtlas; + std::shared_ptr<Sprite> sprite; Placement placement; }; diff --git a/include/mbgl/renderer/symbol_bucket.hpp b/include/mbgl/renderer/symbol_bucket.hpp index a073856d2b..b1917a93b2 100644 --- a/include/mbgl/renderer/symbol_bucket.hpp +++ b/include/mbgl/renderer/symbol_bucket.hpp @@ -24,6 +24,7 @@ class IconShader; class DotShader; class Placement; class SpriteAtlas; +class Sprite; class GlyphAtlas; class GlyphStore; class FontStack; @@ -44,8 +45,8 @@ public: virtual bool hasIconData() const; void addFeatures(const VectorTileLayer &layer, const FilterExpression &filter, - const Tile::ID &id, SpriteAtlas &spriteAtlas, GlyphAtlas &glyphAtlas, - GlyphStore &glyphStore); + const Tile::ID &id, SpriteAtlas &spriteAtlas, Sprite &sprite, + GlyphAtlas &glyphAtlas, GlyphStore &glyphStore); void addGlyphs(const PlacedGlyphs &glyphs, float placementZoom, PlacementRange placementRange, float zoom); diff --git a/include/mbgl/style/style.hpp b/include/mbgl/style/style.hpp index 6aab71a4c6..3df58ab42b 100644 --- a/include/mbgl/style/style.hpp +++ b/include/mbgl/style/style.hpp @@ -48,13 +48,15 @@ public: const BackgroundProperties &getBackgroundProperties() const; + const std::string &getSpriteURL() const; + public: - std::shared_ptr<Sprite> sprite; std::shared_ptr<StyleLayerGroup> layers; std::vector<std::string> appliedClasses; - std::string sprite_url; std::string glyph_url; +private: + std::string sprite_url; private: PropertyTransition defaultTransition; diff --git a/src/geometry/sprite_atlas.cpp b/src/geometry/sprite_atlas.cpp index 8fa3e83888..71d3cbee99 100644 --- a/src/geometry/sprite_atlas.cpp +++ b/src/geometry/sprite_atlas.cpp @@ -88,27 +88,6 @@ void copy_bitmap(const uint32_t *src, const int src_stride, const int src_x, con } } -void draw_circle(uint32_t *dst, const int dst_stride, const int dst_x, const int dst_y, - const int width, const int height, const float blur, - const uint8_t r = 0xFF, const uint8_t g = 0xFF, const uint8_t b = 0xFF) { - const int sprite_stride = dst_stride; - const int radius = util::min(width, height); - for (int y = 0; y < height; y++) { - const int img_y = (dst_y + y) * sprite_stride + dst_x; - for (int x = 0; x < height; x++) { - const float dist = util::length(float(x) / radius - 0.5f, float(y) / radius - 0.5f); - const float t = util::smoothstep(0.5f, 0.5f - blur, dist); - const uint8_t alpha = t * 255; - - uint32_t color = (uint32_t(r * t) << 0) | - (uint32_t(g * t) << 8) | - (uint32_t(b * t) << 16) | - (uint32_t(alpha) << 24); - dst[img_y + x] = color; - } - } -} - Rect<SpriteAtlas::dimension> SpriteAtlas::allocateImage(size_t width, size_t height) { // We have to allocate a new area in the bin, and store an empty image in it. // Add a 1px border around every image. @@ -125,44 +104,6 @@ Rect<SpriteAtlas::dimension> SpriteAtlas::allocateImage(size_t width, size_t hei return rect; } -Rect<SpriteAtlas::dimension> SpriteAtlas::getIcon(const int size, const std::string &name) { - std::lock_guard<std::mutex> lock(mtx); - - auto rect_it = images.find(name); - if (rect_it != images.end()) { - return rect_it->second; - } - - Rect<dimension> rect = allocateImage(size, size); - if (rect.w == 0) { - if (debug::spriteWarnings) { - fprintf(stderr, "[WARNING] sprite atlas bitmap overflow\n"); - } - return rect; - } - - images.emplace(name, rect); - - allocate(); - - // Draw an antialiased circle. - draw_circle( - reinterpret_cast<uint32_t *>(data), - width * pixelRatio, - rect.x * pixelRatio, - rect.y * pixelRatio, - size * pixelRatio, - size * pixelRatio, - 1.0f / size / pixelRatio - ); - - uninitialized.emplace(name); - - dirty = true; - - return rect; -} - Rect<SpriteAtlas::dimension> SpriteAtlas::getImage(const std::string &name, const Sprite &sprite) { std::lock_guard<std::mutex> lock(mtx); @@ -191,6 +132,12 @@ Rect<SpriteAtlas::dimension> SpriteAtlas::getImage(const std::string &name, cons return rect; } + +Rect<SpriteAtlas::dimension> SpriteAtlas::waitForImage(const std::string &name, const Sprite &sprite) { + sprite.waitUntilLoaded(); + return getImage(name, sprite); +} + void SpriteAtlas::allocate() { if (!data) { dimension w = static_cast<dimension>(width * pixelRatio); diff --git a/src/map/map.cpp b/src/map/map.cpp index ca43662e09..269d174c8c 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -201,6 +201,17 @@ std::string Map::getAccessToken() const { return accessToken; } +std::shared_ptr<Sprite> Map::getSprite() { + float pixelRatio = state.getPixelRatio(); + const std::string &sprite_url = style->getSpriteURL(); + if (!sprite || sprite->pixelRatio != pixelRatio || sprite->url != sprite_url) { + sprite = Sprite::Create(sprite_url, pixelRatio); + } + + return sprite; +} + + #pragma mark - Size // Note: This function is called from another thread. Make sure you only call threadsafe functions! @@ -502,14 +513,6 @@ void Map::prepare() { bool dimensionsChanged = oldState.getFramebufferWidth() != state.getFramebufferWidth() || oldState.getFramebufferHeight() != state.getFramebufferHeight(); - if (pixelRatioChanged) { - style->sprite = std::make_shared<Sprite>(*this, state.getPixelRatio()); - if (style->sprite_url.size()) { - style->sprite->load(style->sprite_url); - } - spriteAtlas->resize(state.getPixelRatio()); - } - // Create a new glyph store object in case the glyph URL changed. // TODO: Move this to a less frequently called place; we only need to do this when the // stylesheet changes. @@ -528,11 +531,13 @@ void Map::prepare() { updateSources(); style->updateProperties(state.getNormalizedZoom(), animationTime); - // Allow the sprite atlas to potentially pull new sprite images if needed. - if (style->sprite && style->sprite->isLoaded()) { - spriteAtlas->update(*style->sprite); + if (pixelRatioChanged) { + spriteAtlas->resize(state.getPixelRatio()); } + // Allow the sprite atlas to potentially pull new sprite images if needed. + spriteAtlas->update(*getSprite()); + updateTiles(); } diff --git a/src/map/sprite.cpp b/src/map/sprite.cpp index 60f19ab006..6cf40f23f9 100644 --- a/src/map/sprite.cpp +++ b/src/map/sprite.cpp @@ -20,48 +20,75 @@ SpritePosition::SpritePosition(uint16_t x, uint16_t y, uint16_t width, uint16_t pixelRatio(pixelRatio) { } -Sprite::Sprite(Map &map, float pixelRatio) +std::shared_ptr<Sprite> Sprite::Create(const std::string& base_url, float pixelRatio) { + std::shared_ptr<Sprite> sprite(std::make_shared<Sprite>(Key(), base_url, pixelRatio)); + sprite->load(); + return sprite; +} + +Sprite::Sprite(const Key &, const std::string& base_url, float pixelRatio) : pixelRatio(pixelRatio), + url(base_url), raster(), - map(map), loadedImage(false), - loadedJSON(false) { + loadedJSON(false), + future(promise.get_future()) { +} + +void Sprite::waitUntilLoaded() const { + future.wait(); } -void Sprite::load(const std::string& base_url) { - loadedImage = false; - loadedJSON = false; +Sprite::operator bool() const { + return isLoaded() && !pos.empty(); +} + + +// Note: This is a separate function that must be called exactly once after creation +// The reason this isn't part of the constructor is that calling shared_from_this() in +// the constructor fails. +void Sprite::load() { + if (url.length() == 0) { + // Treat a non-existent sprite as an empty sprite. + loadedImage = true; + loadedJSON = true; + promise.set_value(); + return; + } - url = base_url; std::shared_ptr<Sprite> sprite = shared_from_this(); - std::string suffix = (pixelRatio > 1 ? "@2x" : ""); + const std::string suffix = (pixelRatio > 1 ? "@2x" : ""); - platform::request_http(base_url + suffix + ".json", [sprite](platform::Response *res) { + platform::request_http(url + suffix + ".json", [sprite](platform::Response *res) { if (res->code == 200) { sprite->body.swap(res->body); - sprite->asyncParseJSON(); + sprite->parseJSON(); + sprite->complete(); } else { fprintf(stderr, "failed to load sprite info\n"); fprintf(stderr, "error %d: %s\n", res->code, res->error_message.c_str()); + sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res->error_message))); } - }, map.getLoop()); + }); - platform::request_http(base_url + suffix + ".png", [sprite](platform::Response *res) { + platform::request_http(url + suffix + ".png", [sprite](platform::Response *res) { if (res->code == 200) { - sprite->image.swap(res->body); - sprite->asyncParseImage(); + sprite->image.swap(res->body); + sprite->parseImage(); + sprite->complete(); } else { fprintf(stderr, "failed to load sprite image\n"); fprintf(stderr, "error %d: %s\n", res->code, res->error_message.c_str()); + sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res->error_message))); } - }, map.getLoop()); + }); } -void Sprite::complete(std::shared_ptr<Sprite> &sprite) { - if (sprite->loadedImage && sprite->loadedJSON) { - sprite->map.update(); - Log::Info(Event::Sprite, "loaded %s", sprite->url.c_str()); +void Sprite::complete() { + if (loadedImage && loadedJSON) { + Log::Info(Event::Sprite, "loaded %s", url.c_str()); + promise.set_value(); } } @@ -69,28 +96,20 @@ bool Sprite::isLoaded() const { return loadedImage && loadedJSON; } -void Sprite::asyncParseImage() { - new uv::work<std::shared_ptr<Sprite>>(map.getLoop(), parseImage, complete, shared_from_this()); +void Sprite::parseImage() { + raster = std::make_unique<util::Image>(image); + image.clear(); + loadedImage = true; } -void Sprite::asyncParseJSON() { - new uv::work<std::shared_ptr<Sprite>>(map.getLoop(), parseJSON, complete, shared_from_this()); -} - -void Sprite::parseImage(std::shared_ptr<Sprite> &sprite) { - sprite->raster = std::make_unique<util::Image>(sprite->image); - sprite->image.clear(); - sprite->loadedImage = true; -} - -void Sprite::parseJSON(std::shared_ptr<Sprite> &sprite) { +void Sprite::parseJSON() { rapidjson::Document d; - d.Parse<0>(sprite->body.c_str()); - sprite->body.clear(); - - if (d.IsObject()) { - std::unordered_map<std::string, SpritePosition> pos; + d.Parse<0>(body.c_str()); + body.clear(); + if (d.HasParseError()) { + Log::Warning(Event::Sprite, "sprite JSON is invalid"); + } else if (d.IsObject()) { for (rapidjson::Value::ConstMemberIterator itr = d.MemberBegin(); itr != d.MemberEnd(); ++itr) { const std::string& name = itr->name.GetString(); const rapidjson::Value& value = itr->value; @@ -110,10 +129,11 @@ void Sprite::parseJSON(std::shared_ptr<Sprite> &sprite) { pos.emplace(name, SpritePosition { x, y, width, height, pixelRatio }); } } - - sprite->pos.swap(pos); - sprite->loadedJSON = true; + } else { + Log::Warning(Event::Sprite, "sprite JSON root is not an object"); } + + loadedJSON = true; } const SpritePosition &Sprite::getSpritePosition(const std::string& name) const { diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 6be9bcb32c..99ee676237 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -34,13 +34,15 @@ TileParser::TileParser(const std::string &data, VectorTileData &tile, const std::shared_ptr<const Style> &style, const std::shared_ptr<GlyphAtlas> &glyphAtlas, const std::shared_ptr<GlyphStore> &glyphStore, - const std::shared_ptr<SpriteAtlas> &spriteAtlas) + const std::shared_ptr<SpriteAtlas> &spriteAtlas, + const std::shared_ptr<Sprite> &sprite) : vector_data(pbf((const uint8_t *)data.data(), data.size())), tile(tile), style(style), glyphAtlas(glyphAtlas), glyphStore(glyphStore), spriteAtlas(spriteAtlas), + sprite(sprite), placement(tile.id.z, tile.id.z >= tile.source.max_zoom ? tile.source.max_zoom - tile.id.z : 1) { } @@ -153,6 +155,6 @@ std::unique_ptr<Bucket> TileParser::createLineBucket(const VectorTileLayer& laye std::unique_ptr<Bucket> TileParser::createSymbolBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketSymbol &symbol) { std::unique_ptr<SymbolBucket> bucket = std::make_unique<SymbolBucket>(tile.textVertexBuffer, tile.iconVertexBuffer, tile.triangleElementsBuffer, symbol, placement); - bucket->addFeatures(layer, filter, tile.id, *spriteAtlas, *glyphAtlas, *glyphStore); + bucket->addFeatures(layer, filter, tile.id, *spriteAtlas, *sprite, *glyphAtlas, *glyphStore); return obsolete() ? nullptr : std::move(bucket); } diff --git a/src/map/vector_tile_data.cpp b/src/map/vector_tile_data.cpp index fd3cd6ec8c..99c521b8ab 100644 --- a/src/map/vector_tile_data.cpp +++ b/src/map/vector_tile_data.cpp @@ -20,7 +20,7 @@ VectorTileData::~VectorTileData() { } void VectorTileData::beforeParse() { - parser = std::make_unique<TileParser>(data, *this, map.getStyle(), map.getGlyphAtlas(), map.getGlyphStore(), map.getSpriteAtlas()); + parser = std::make_unique<TileParser>(data, *this, map.getStyle(), map.getGlyphAtlas(), map.getGlyphStore(), map.getSpriteAtlas(), map.getSprite()); } void VectorTileData::parse() { diff --git a/src/renderer/painter_fill.cpp b/src/renderer/painter_fill.cpp index 7664555b7a..29d77e05d9 100644 --- a/src/renderer/painter_fill.cpp +++ b/src/renderer/painter_fill.cpp @@ -71,10 +71,10 @@ void Painter::renderFill(FillBucket& bucket, const FillProperties& properties, c } if ((fill_color[3] >= 1.0f) == (pass == Opaque)) { - const std::shared_ptr<Sprite> &sprite = map.getStyle()->sprite; + Sprite &sprite = *map.getSprite(); if (properties.image.size() && sprite) { SpriteAtlas &spriteAtlas = *map.getSpriteAtlas(); - Rect<uint16_t> imagePos = spriteAtlas.getImage(properties.image, *sprite); + Rect<uint16_t> imagePos = spriteAtlas.getImage(properties.image, sprite); float factor = 8.0 / std::pow(2, map.getState().getIntegerZoom() - id.z); diff --git a/src/renderer/symbol_bucket.cpp b/src/renderer/symbol_bucket.cpp index 60fd6e240a..f09f87da0a 100644 --- a/src/renderer/symbol_bucket.cpp +++ b/src/renderer/symbol_bucket.cpp @@ -62,7 +62,7 @@ void SymbolBucket::addGlyph(uint64_t tileid, const std::string stackname, } void SymbolBucket::addFeatures(const VectorTileLayer &layer, const FilterExpression &filter, - const Tile::ID &id, SpriteAtlas &spriteAtlas, GlyphAtlas &glyphAtlas, + const Tile::ID &id, SpriteAtlas &spriteAtlas, Sprite &sprite, GlyphAtlas &glyphAtlas, GlyphStore &glyphStore) { const bool text = properties.text.field.size(); const bool icon = properties.icon.image.size(); @@ -106,8 +106,7 @@ void SymbolBucket::addFeatures(const VectorTileLayer &layer, const FilterExpress if (icon) { std::string field = util::replaceTokens(properties.icon.image, feature.properties); - // TODO: remove hardcoded size 12. - const Rect<uint16_t> rect = spriteAtlas.getIcon(12, field); + const Rect<uint16_t> rect = spriteAtlas.waitForImage(field, sprite); const uint16_t tx = rect.x + rect.w / 2; const uint16_t ty = rect.y + rect.h / 2; diff --git a/src/style/style.cpp b/src/style/style.cpp index f867616970..76ee3707bc 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -1,4 +1,5 @@ #include <mbgl/style/style.hpp> +#include <mbgl/map/sprite.hpp> #include <mbgl/style/style_layer_group.hpp> #include <mbgl/style/style_parser.hpp> #include <mbgl/style/style_bucket.hpp> @@ -29,6 +30,10 @@ void Style::updateProperties(float z, timestamp now) { } } +const std::string &Style::getSpriteURL() const { + return sprite_url; +} + void Style::setDefaultTransitionDuration(uint16_t duration_milliseconds) { defaultTransition.duration = duration_milliseconds; } |