diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2016-09-15 15:40:35 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2016-09-19 09:40:43 -0700 |
commit | 940124ff713a960d7f70071779dd37d07010fa80 (patch) | |
tree | a89c129b9e972946ab29f05587381c45649a5d99 /src/mbgl/sprite | |
parent | 1014a503a22dc47e4e6ec3c37d034fd729873345 (diff) | |
download | qtlocation-mapboxgl-940124ff713a960d7f70071779dd37d07010fa80.tar.gz |
[core] Merge SpriteStore and SpriteAtlas
Diffstat (limited to 'src/mbgl/sprite')
-rw-r--r-- | src/mbgl/sprite/sprite_atlas.cpp | 164 | ||||
-rw-r--r-- | src/mbgl/sprite/sprite_atlas.hpp | 55 | ||||
-rw-r--r-- | src/mbgl/sprite/sprite_atlas_observer.hpp (renamed from src/mbgl/sprite/sprite_store_observer.hpp) | 4 | ||||
-rw-r--r-- | src/mbgl/sprite/sprite_store.cpp | 158 | ||||
-rw-r--r-- | src/mbgl/sprite/sprite_store.hpp | 70 |
5 files changed, 200 insertions, 251 deletions
diff --git a/src/mbgl/sprite/sprite_atlas.cpp b/src/mbgl/sprite/sprite_atlas.cpp index d346464b51..78d5fe638a 100644 --- a/src/mbgl/sprite/sprite_atlas.cpp +++ b/src/mbgl/sprite/sprite_atlas.cpp @@ -1,5 +1,6 @@ #include <mbgl/sprite/sprite_atlas.hpp> -#include <mbgl/sprite/sprite_store.hpp> +#include <mbgl/sprite/sprite_atlas_observer.hpp> +#include <mbgl/sprite/sprite_parser.hpp> #include <mbgl/gl/gl.hpp> #include <mbgl/gl/gl_config.hpp> #include <mbgl/platform/log.hpp> @@ -7,6 +8,10 @@ #include <mbgl/util/math.hpp> #include <mbgl/util/std.hpp> #include <mbgl/util/constants.hpp> +#include <mbgl/util/exception.hpp> +#include <mbgl/storage/file_source.hpp> +#include <mbgl/storage/resource.hpp> +#include <mbgl/storage/response.hpp> #include <cassert> #include <cmath> @@ -14,15 +19,147 @@ namespace mbgl { -SpriteAtlas::SpriteAtlas(dimension width_, dimension height_, float pixelRatio_, SpriteStore& store_) +static SpriteAtlasObserver nullObserver; + +struct SpriteAtlas::Loader { + std::shared_ptr<const std::string> image; + std::shared_ptr<const std::string> json; + std::unique_ptr<AsyncRequest> jsonRequest; + std::unique_ptr<AsyncRequest> spriteRequest; +}; + +SpriteAtlas::SpriteAtlas(dimension width_, dimension height_, float pixelRatio_) : width(width_), height(height_), pixelWidth(std::ceil(width * pixelRatio_)), pixelHeight(std::ceil(height * pixelRatio_)), pixelRatio(pixelRatio_), - store(store_), + observer(&nullObserver), bin(width_, height_), - dirty(true) { + dirtyFlag(true) { +} + +SpriteAtlas::~SpriteAtlas() = default; + +void SpriteAtlas::load(const std::string& url, FileSource& fileSource) { + if (url.empty()) { + // Treat a non-existent sprite as a successfully loaded empty sprite. + loaded = true; + return; + } + + loader = std::make_unique<Loader>(); + + loader->jsonRequest = fileSource.request(Resource::spriteJSON(url, pixelRatio), [this](Response res) { + if (res.error) { + observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message))); + } else if (res.notModified) { + return; + } else if (res.noContent) { + loader->json = std::make_shared<const std::string>(); + emitSpriteLoadedIfComplete(); + } else { + // Only trigger a sprite loaded event we got new data. + loader->json = res.data; + emitSpriteLoadedIfComplete(); + } + }); + + loader->spriteRequest = fileSource.request(Resource::spriteImage(url, pixelRatio), [this](Response res) { + if (res.error) { + observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message))); + } else if (res.notModified) { + return; + } else if (res.noContent) { + loader->image = std::make_shared<const std::string>(); + emitSpriteLoadedIfComplete(); + } else { + loader->image = res.data; + emitSpriteLoadedIfComplete(); + } + }); +} + +void SpriteAtlas::emitSpriteLoadedIfComplete() { + assert(loader); + + if (!loader->image || !loader->json) { + return; + } + + auto result = parseSprite(*loader->image, *loader->json); + if (result.is<Sprites>()) { + loaded = true; + setSprites(result.get<Sprites>()); + observer->onSpriteLoaded(); + } else { + observer->onSpriteError(result.get<std::exception_ptr>()); + } +} + +void SpriteAtlas::setObserver(SpriteAtlasObserver* observer_) { + observer = observer_; +} + +void SpriteAtlas::dumpDebugLogs() const { + Log::Info(Event::General, "SpriteAtlas::loaded: %d", loaded); +} + +void SpriteAtlas::setSprites(const Sprites& newSprites) { + std::lock_guard<std::mutex> lock(mutex); + for (const auto& pair : newSprites) { + _setSprite(pair.first, pair.second); + } +} + +void SpriteAtlas::setSprite(const std::string& name, std::shared_ptr<const SpriteImage> sprite) { + std::lock_guard<std::mutex> lock(mutex); + _setSprite(name, sprite); +} + +void SpriteAtlas::removeSprite(const std::string& name) { + std::lock_guard<std::mutex> lock(mutex); + _setSprite(name); +} + +void SpriteAtlas::_setSprite(const std::string& name, + const std::shared_ptr<const SpriteImage>& sprite) { + if (sprite) { + auto it = sprites.find(name); + if (it != sprites.end()) { + // There is already a sprite with that name in our store. + if ((it->second->image.width != sprite->image.width || it->second->image.height != sprite->image.height)) { + Log::Warning(Event::Sprite, "Can't change sprite dimensions for '%s'", name.c_str()); + return; + } + it->second = sprite; + } else { + sprites.emplace(name, sprite); + } + + // Always add/replace the value in the dirty list. + auto dirty_it = dirtySprites.find(name); + if (dirty_it != dirtySprites.end()) { + dirty_it->second = sprite; + } else { + dirtySprites.emplace(name, sprite); + } + } else if (sprites.erase(name) > 0) { + dirtySprites.emplace(name, nullptr); + } +} + +std::shared_ptr<const SpriteImage> SpriteAtlas::getSprite(const std::string& name) { + std::lock_guard<std::mutex> lock(mutex); + const auto it = sprites.find(name); + if (it != sprites.end()) { + return it->second; + } else { + if (!sprites.empty()) { + Log::Info(Event::Sprite, "Can't find sprite named '%s'", name.c_str()); + } + return nullptr; + } } Rect<SpriteAtlas::dimension> SpriteAtlas::allocateImage(const SpriteImage& spriteImage) { @@ -55,7 +192,7 @@ optional<SpriteAtlasElement> SpriteAtlas::getImage(const std::string& name, return SpriteAtlasElement { rect_it->second.pos, rect_it->second.spriteImage, rect_it->second.spriteImage->pixelRatio / pixelRatio }; } - auto sprite = store.getSprite(name); + auto sprite = getSprite(name); if (!sprite) { return {}; } @@ -142,21 +279,16 @@ void SpriteAtlas::copy(const Holder& holder, const SpritePatternMode mode) { dstData, pixelWidth, (holder.pos.x + padding) * pixelRatio, (holder.pos.y + padding) * pixelRatio, pixelWidth * pixelHeight, uint32_t(holder.spriteImage->image.width), uint32_t(holder.spriteImage->image.height), mode); - dirty = true; + dirtyFlag = true; } void SpriteAtlas::upload(gl::ObjectStore& objectStore, gl::Config& config, uint32_t unit) { - if (dirty) { + if (dirtyFlag) { bind(false, objectStore, config, unit); } } void SpriteAtlas::updateDirty() { - auto dirtySprites = store.getDirty(); - if (dirtySprites.empty()) { - return; - } - std::lock_guard<std::recursive_mutex> lock(mtx); auto imageIterator = images.begin(); @@ -180,6 +312,8 @@ void SpriteAtlas::updateDirty() { // name, but a different wrap value. } } + + dirtySprites.clear(); } void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore, gl::Config& config, uint32_t unit) { @@ -212,7 +346,7 @@ void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore, gl::Config& co filter = filter_val; } - if (dirty) { + if (dirtyFlag) { std::lock_guard<std::recursive_mutex> lock(mtx); config.activeTexture = unit; @@ -243,7 +377,7 @@ void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore, gl::Config& co )); } - dirty = false; + dirtyFlag = false; #ifndef GL_ES_VERSION_2_0 // platform::showColorDebugImage("Sprite Atlas", reinterpret_cast<const char*>(data.get()), @@ -252,8 +386,6 @@ void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore, gl::Config& co } } -SpriteAtlas::~SpriteAtlas() = default; - SpriteAtlas::Holder::Holder(std::shared_ptr<const SpriteImage> spriteImage_, Rect<dimension> pos_) : spriteImage(std::move(spriteImage_)), pos(std::move(pos_)) { } diff --git a/src/mbgl/sprite/sprite_atlas.hpp b/src/mbgl/sprite/sprite_atlas.hpp index d7901244cb..d23d3a0fd1 100644 --- a/src/mbgl/sprite/sprite_atlas.hpp +++ b/src/mbgl/sprite/sprite_atlas.hpp @@ -5,6 +5,7 @@ #include <mbgl/gl/object_store.hpp> #include <mbgl/util/noncopyable.hpp> #include <mbgl/util/optional.hpp> +#include <mbgl/sprite/sprite_image.hpp> #include <atomic> #include <string> @@ -12,14 +13,17 @@ #include <mutex> #include <set> #include <array> +#include <memory> namespace mbgl { +class FileSource; +class SpriteAtlasObserver; + namespace gl { class Config; } // namespace gl -class SpriteStore; class SpriteImage; class SpritePosition; @@ -43,10 +47,33 @@ enum class SpritePatternMode : bool { class SpriteAtlas : public util::noncopyable { public: typedef uint16_t dimension; + using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>; - SpriteAtlas(dimension width, dimension height, float pixelRatio, SpriteStore& store); + SpriteAtlas(dimension width, dimension height, float pixelRatio); ~SpriteAtlas(); + void load(const std::string& url, FileSource&); + + bool isLoaded() const { + return loaded; + } + + void dumpDebugLogs() const; + + void setObserver(SpriteAtlasObserver*); + + // Adds/replaces a Sprite image. + void setSprite(const std::string&, std::shared_ptr<const SpriteImage>); + + // Adds/replaces mutliple Sprite images. + void setSprites(const Sprites& sprites); + + // Removes a Sprite. + void removeSprite(const std::string&); + + // Obtains a Sprite image. + std::shared_ptr<const SpriteImage> getSprite(const std::string&); + // If the sprite is loaded, copies the requsted image from it into the atlas and returns // the resulting icon measurements. If not, returns an empty optional. optional<SpriteAtlasElement> getImage(const std::string& name, SpritePatternMode mode); @@ -58,7 +85,7 @@ public: // Binds the atlas texture to the GPU, and uploads data if it is out of date. void bind(bool linear, gl::ObjectStore&, gl::Config&, uint32_t unit); - // Updates sprites in the atlas texture that may have changed in the source SpriteStore object. + // Updates sprites in the atlas texture that may have changed. void updateDirty(); // Uploads the texture to the GPU to be available when we need it. This is a lazy operation; @@ -75,10 +102,29 @@ public: const uint32_t* getData() const { return data.get(); } private: + void _setSprite(const std::string&, const std::shared_ptr<const SpriteImage>& = nullptr); + void emitSpriteLoadedIfComplete(); + const GLsizei width, height; const dimension pixelWidth, pixelHeight; const float pixelRatio; + struct Loader; + std::unique_ptr<Loader> loader; + + bool loaded = false; + + SpriteAtlasObserver* observer = nullptr; + + // Lock for sprites and dirty maps. + std::mutex mutex; + + // Stores all current sprites. + Sprites sprites; + + // Stores all Sprite IDs that changed since the last invocation. + Sprites dirtySprites; + struct Holder : private util::noncopyable { Holder(std::shared_ptr<const SpriteImage>, Rect<dimension>); Holder(Holder&&); @@ -92,12 +138,11 @@ private: void copy(const Holder& holder, SpritePatternMode mode); std::recursive_mutex mtx; - SpriteStore& store; BinPack<dimension> bin; std::map<Key, Holder> images; std::set<std::string> uninitialized; std::unique_ptr<uint32_t[]> data; - std::atomic<bool> dirty; + std::atomic<bool> dirtyFlag; bool fullUploadRequired = true; mbgl::optional<gl::UniqueTexture> texture; uint32_t filter = 0; diff --git a/src/mbgl/sprite/sprite_store_observer.hpp b/src/mbgl/sprite/sprite_atlas_observer.hpp index 32ce040aa4..263c95b0e8 100644 --- a/src/mbgl/sprite/sprite_store_observer.hpp +++ b/src/mbgl/sprite/sprite_atlas_observer.hpp @@ -4,9 +4,9 @@ namespace mbgl { -class SpriteStoreObserver { +class SpriteAtlasObserver { public: - virtual ~SpriteStoreObserver() = default; + virtual ~SpriteAtlasObserver() = default; virtual void onSpriteLoaded() {} virtual void onSpriteError(std::exception_ptr) {} diff --git a/src/mbgl/sprite/sprite_store.cpp b/src/mbgl/sprite/sprite_store.cpp deleted file mode 100644 index b9249a3ffc..0000000000 --- a/src/mbgl/sprite/sprite_store.cpp +++ /dev/null @@ -1,158 +0,0 @@ -#include <mbgl/sprite/sprite_store.hpp> -#include <mbgl/sprite/sprite_store_observer.hpp> -#include <mbgl/sprite/sprite_parser.hpp> -#include <mbgl/platform/log.hpp> -#include <mbgl/storage/file_source.hpp> -#include <mbgl/storage/resource.hpp> -#include <mbgl/storage/response.hpp> -#include <mbgl/util/exception.hpp> - -#include <cassert> -#include <string> - -namespace mbgl { - -static SpriteStoreObserver nullObserver; - -struct SpriteStore::Loader { - std::shared_ptr<const std::string> image; - std::shared_ptr<const std::string> json; - std::unique_ptr<AsyncRequest> jsonRequest; - std::unique_ptr<AsyncRequest> spriteRequest; -}; - -SpriteStore::SpriteStore(float pixelRatio_) - : pixelRatio(pixelRatio_ > 1 ? 2 : 1), observer(&nullObserver) { -} - -SpriteStore::~SpriteStore() = default; - -void SpriteStore::load(const std::string& url, FileSource& fileSource) { - if (url.empty()) { - // Treat a non-existent sprite as a successfully loaded empty sprite. - loaded = true; - return; - } - - loader = std::make_unique<Loader>(); - - loader->jsonRequest = fileSource.request(Resource::spriteJSON(url, pixelRatio), [this](Response res) { - if (res.error) { - observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message))); - } else if (res.notModified) { - return; - } else if (res.noContent) { - loader->json = std::make_shared<const std::string>(); - emitSpriteLoadedIfComplete(); - } else { - // Only trigger a sprite loaded event we got new data. - loader->json = res.data; - emitSpriteLoadedIfComplete(); - } - }); - - loader->spriteRequest = fileSource.request(Resource::spriteImage(url, pixelRatio), [this](Response res) { - if (res.error) { - observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message))); - } else if (res.notModified) { - return; - } else if (res.noContent) { - loader->image = std::make_shared<const std::string>(); - emitSpriteLoadedIfComplete(); - } else { - loader->image = res.data; - emitSpriteLoadedIfComplete(); - } - }); -} - -void SpriteStore::emitSpriteLoadedIfComplete() { - assert(loader); - - if (!loader->image || !loader->json) { - return; - } - - auto result = parseSprite(*loader->image, *loader->json); - if (result.is<Sprites>()) { - loaded = true; - setSprites(result.get<Sprites>()); - observer->onSpriteLoaded(); - } else { - observer->onSpriteError(result.get<std::exception_ptr>()); - } -} - -void SpriteStore::setObserver(SpriteStoreObserver* observer_) { - observer = observer_; -} - -void SpriteStore::dumpDebugLogs() const { - Log::Info(Event::General, "SpriteStore::loaded: %d", loaded); -} - -void SpriteStore::setSprite(const std::string& name, std::shared_ptr<const SpriteImage> sprite) { - std::lock_guard<std::mutex> lock(mutex); - _setSprite(name, sprite); -} - -void SpriteStore::_setSprite(const std::string& name, - const std::shared_ptr<const SpriteImage>& sprite) { - if (sprite) { - auto it = sprites.find(name); - if (it != sprites.end()) { - // There is already a sprite with that name in our store. - if ((it->second->image.width != sprite->image.width || it->second->image.height != sprite->image.height)) { - Log::Warning(Event::Sprite, "Can't change sprite dimensions for '%s'", name.c_str()); - return; - } - it->second = sprite; - } else { - sprites.emplace(name, sprite); - } - - // Always add/replace the value in the dirty list. - auto dirty_it = dirty.find(name); - if (dirty_it != dirty.end()) { - dirty_it->second = sprite; - } else { - dirty.emplace(name, sprite); - } - } else if (sprites.erase(name) > 0) { - dirty.emplace(name, nullptr); - } -} - -void SpriteStore::setSprites(const Sprites& newSprites) { - std::lock_guard<std::mutex> lock(mutex); - for (const auto& pair : newSprites) { - _setSprite(pair.first, pair.second); - } -} - -void SpriteStore::removeSprite(const std::string& name) { - std::lock_guard<std::mutex> lock(mutex); - _setSprite(name); -} - -std::shared_ptr<const SpriteImage> SpriteStore::getSprite(const std::string& name) { - std::lock_guard<std::mutex> lock(mutex); - const auto it = sprites.find(name); - if (it != sprites.end()) { - return it->second; - } else { - if (!sprites.empty()) { - Log::Info(Event::Sprite, "Can't find sprite named '%s'", name.c_str()); - } - return nullptr; - } -} - -SpriteStore::Sprites SpriteStore::getDirty() { - Sprites result; - std::lock_guard<std::mutex> lock(mutex); - dirty.swap(result); - return result; -} - -} // namespace mbgl diff --git a/src/mbgl/sprite/sprite_store.hpp b/src/mbgl/sprite/sprite_store.hpp deleted file mode 100644 index c6f34d6c5e..0000000000 --- a/src/mbgl/sprite/sprite_store.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include <mbgl/sprite/sprite_image.hpp> -#include <mbgl/util/noncopyable.hpp> - -#include <map> -#include <memory> -#include <mutex> - -namespace mbgl { - -class FileSource; -class SpriteStoreObserver; - -class SpriteStore : private util::noncopyable { -public: - using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>; - - SpriteStore(float pixelRatio); - ~SpriteStore(); - - void load(const std::string& url, FileSource&); - - bool isLoaded() const { - return loaded; - } - - void dumpDebugLogs() const; - - void setObserver(SpriteStoreObserver* observer); - - // Adds/replaces a Sprite image. - void setSprite(const std::string&, std::shared_ptr<const SpriteImage> = nullptr); - - // Adds/replaces mutliple Sprite images. - void setSprites(const Sprites& sprites); - - // Removes a Sprite. - void removeSprite(const std::string&); - - // Obtains a Sprite image. - std::shared_ptr<const SpriteImage> getSprite(const std::string&); - - // Returns Sprite images that changed since the last invocation of this function. - Sprites getDirty(); - - const float pixelRatio; - -private: - void _setSprite(const std::string&, const std::shared_ptr<const SpriteImage>& = nullptr); - void emitSpriteLoadedIfComplete(); - - struct Loader; - std::unique_ptr<Loader> loader; - - bool loaded = false; - - SpriteStoreObserver* observer = nullptr; - - // Lock for sprites and dirty maps. - std::mutex mutex; - - // Stores all current sprites. - Sprites sprites; - - // Stores all Sprite IDs that changed since the last invocation. - Sprites dirty; -}; - -} // namespace mbgl |