diff --git a/include/llmr/style/sprite.hpp b/include/llmr/style/sprite.hpp index fa0f86ecf..ea1a29dff 100644 --- a/include/llmr/style/sprite.hpp +++ b/include/llmr/style/sprite.hpp @@ -49,8 +49,10 @@ public: private: void asyncParseJSON(); + void asyncParseImage(); static void parseJSON(std::shared_ptr &sprite); + static void parseImage(std::shared_ptr &sprite); static void complete(std::shared_ptr &sprite); private: diff --git a/include/llmr/util/raster.hpp b/include/llmr/util/raster.hpp index afb37b30b..229d32c01 100644 --- a/include/llmr/util/raster.hpp +++ b/include/llmr/util/raster.hpp @@ -8,6 +8,8 @@ #include #include +typedef struct uv_loop_s uv_loop_t; + namespace llmr { class Raster : public std::enable_shared_from_this { @@ -16,7 +18,7 @@ public: ~Raster(); // load image data - void load(const std::string& data); + void load(); // set shared texture pool void setTexturepool(Texturepool* texturepool); @@ -25,13 +27,15 @@ public: void bind(bool linear = false); // loaded status - operator bool() const; + bool isLoaded() const; // animations void beginFadeInAnimation(); bool needsAnimation() const; void updateAnimations(double time); + inline void setData(const std::string &img) { data = img; } + public: // loaded image dimensions uint32_t width = 0, height = 0; @@ -61,6 +65,9 @@ private: // min/mag filter uint32_t filter = 0; + // the encoded image data. + std::string data; + // the raw pixels char *img = nullptr; diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index ed8ad14e4..48fc24718 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -84,7 +84,8 @@ std::unique_ptr TileParser::createBucket(const BucketDescription& bucket if (bucket_desc.type == BucketType::Raster) { if (raster_data.length()) { tile.raster = std::make_shared(); - tile.raster->load(raster_data); + tile.raster->setData(raster_data); + tile.raster->load(); } return createRasterBucket(bucket_desc); } else { diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 73b5779cf..f024fd386 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -542,7 +542,7 @@ void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, co #endif pointShader->setPointTopLeft({{ imagePos.tl.x, imagePos.tl.y }}); pointShader->setPointBottomRight({{ imagePos.br.x, imagePos.br.y }}); - if (*sprite->raster) { + if (sprite->raster->isLoaded()) { sprite->raster->bind(map.getState().isChanging()); } glDepthRange(strata, 1.0f); diff --git a/src/style/sprite.cpp b/src/style/sprite.cpp index 74aa9fa73..408ed11f0 100644 --- a/src/style/sprite.cpp +++ b/src/style/sprite.cpp @@ -40,9 +40,8 @@ void Sprite::load(const std::string& base_url) { platform::request_http(base_url + suffix + ".png", [sprite](platform::Response *res) { if (res->code == 200) { - // TODO: move raster loading to other thread - // TODO: call complete handler - sprite->raster->load(res->body); + sprite->raster->setData(res->body); + sprite->asyncParseImage(); } else { fprintf(stderr, "failed to load sprite image\n"); } @@ -51,7 +50,7 @@ void Sprite::load(const std::string& base_url) { void Sprite::complete(std::shared_ptr &sprite) { std::lock_guard lock(sprite->mtx); - if (*sprite->raster && sprite->pos.size()) { + if (sprite->raster && sprite->raster->isLoaded() && sprite->pos.size()) { sprite->loaded = true; sprite->map.update(); fprintf(stderr, "sprite loaded\n"); @@ -63,11 +62,16 @@ bool Sprite::isLoaded() const { return loaded; } +void Sprite::asyncParseImage() { + new uv::work>(map.getLoop(), parseImage, complete, shared_from_this()); +} + void Sprite::asyncParseJSON() { - new uv::work>(map.getLoop(), - parseJSON, - complete, - shared_from_this()); + new uv::work>(map.getLoop(), parseJSON, complete, shared_from_this()); +} + +void Sprite::parseImage(std::shared_ptr &sprite) { + sprite->raster->load(); } void Sprite::parseJSON(std::shared_ptr &sprite) { @@ -101,7 +105,7 @@ void Sprite::parseJSON(std::shared_ptr &sprite) { } ImagePosition Sprite::getPosition(const std::string& name, bool repeating) { - if (!*this->raster) return {}; + if (!this->raster || !this->raster->isLoaded()) return {}; // `repeating` indicates that the image will be used in a repeating pattern // repeating pattern images are assumed to have a 1px padding that mirrors the opposite edge diff --git a/src/util/raster.cpp b/src/util/raster.cpp index 31eae5951..7741b9f53 100644 --- a/src/util/raster.cpp +++ b/src/util/raster.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -20,20 +21,22 @@ Raster::~Raster() { } } -Raster::operator bool() const { +bool Raster::isLoaded() const { std::lock_guard lock(mtx); return loaded; } -void Raster::load(const std::string& data) { - std::shared_ptr raster = shared_from_this(); +void Raster::load() { + loadImage(data); - raster->loadImage(data); - - std::lock_guard lock(raster->mtx); - if (raster->img) { - raster->loaded = true; + { + std::lock_guard lock(mtx); + if (img) { + loaded = true; + } } + + data.clear(); } struct Buffer {