summaryrefslogtreecommitdiff
path: root/src/mbgl/sprite
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2016-09-15 15:40:35 -0700
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-09-19 09:40:43 -0700
commit940124ff713a960d7f70071779dd37d07010fa80 (patch)
treea89c129b9e972946ab29f05587381c45649a5d99 /src/mbgl/sprite
parent1014a503a22dc47e4e6ec3c37d034fd729873345 (diff)
downloadqtlocation-mapboxgl-940124ff713a960d7f70071779dd37d07010fa80.tar.gz
[core] Merge SpriteStore and SpriteAtlas
Diffstat (limited to 'src/mbgl/sprite')
-rw-r--r--src/mbgl/sprite/sprite_atlas.cpp164
-rw-r--r--src/mbgl/sprite/sprite_atlas.hpp55
-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.cpp158
-rw-r--r--src/mbgl/sprite/sprite_store.hpp70
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