Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
Clean up Sprite
Browse files Browse the repository at this point in the history
* Provide a callback so MapContext can re-render when it loads.
* Cancel in-progress loading rather than relying on keeping it
  alive with a shared_ptr.
* Remove / privatize as much as possible.
  • Loading branch information
jfirebaugh committed Apr 22, 2015
1 parent 1d169f0 commit 776612e
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 61 deletions.
5 changes: 4 additions & 1 deletion src/mbgl/map/map_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@ util::ptr<Sprite> MapContext::getSprite() {
const float pixelRatio = data.getTransformState().getPixelRatio();
const std::string &sprite_url = style->getSpriteURL();
if (!sprite || !sprite->hasPixelRatio(pixelRatio)) {
sprite = Sprite::Create(sprite_url, pixelRatio, env);
sprite = std::make_shared<Sprite>(sprite_url, pixelRatio, env, [this] {
assert(Environment::currentlyOn(ThreadType::Map));
triggerUpdate();
});
}

return sprite;
Expand Down
81 changes: 38 additions & 43 deletions src/mbgl/map/sprite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,84 +23,79 @@ SpritePosition::SpritePosition(uint16_t x_, uint16_t y_, uint16_t width_, uint16
sdf(sdf_) {
}

util::ptr<Sprite> Sprite::Create(const std::string &base_url, float pixelRatio, Environment &env) {
util::ptr<Sprite> sprite(std::make_shared<Sprite>(Key(), base_url, pixelRatio));
sprite->load(env);
return sprite;
}

Sprite::Sprite(const Key &, const std::string& base_url, float pixelRatio_)
: valid(base_url.length() > 0),
pixelRatio(pixelRatio_ > 1 ? 2 : 1),
spriteURL(base_url + (pixelRatio_ > 1 ? "@2x" : "") + ".png"),
jsonURL(base_url + (pixelRatio_ > 1 ? "@2x" : "") + ".json"),
Sprite::Sprite(const std::string& baseUrl, float pixelRatio_, Environment& env, std::function<void ()> callback_)
: pixelRatio(pixelRatio_ > 1 ? 2 : 1),
raster(),
loadedImage(false),
loadedJSON(false),
future(promise.get_future()) {
}

bool Sprite::hasPixelRatio(float ratio) const {
return pixelRatio == (ratio > 1 ? 2 : 1);
}


void Sprite::waitUntilLoaded() const {
future.wait();
}

Sprite::operator bool() const {
return valid && isLoaded() && !pos.empty();
}

future(promise.get_future()),
callback(callback_) {

// 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(Environment &env) {
if (!valid) {
if (baseUrl.empty()) {
// Treat a non-existent sprite as a successfully loaded empty sprite.
loadedImage = true;
loadedJSON = true;
promise.set_value();
return;
}

util::ptr<Sprite> sprite = shared_from_this();
std::string spriteURL(baseUrl + (pixelRatio_ > 1 ? "@2x" : "") + ".png");
std::string jsonURL(baseUrl + (pixelRatio_ > 1 ? "@2x" : "") + ".json");

env.request({ Resource::Kind::JSON, jsonURL }, [sprite](const Response &res) {
jsonRequest = env.request({ Resource::Kind::JSON, jsonURL }, [this](const Response &res) {
jsonRequest = nullptr;
if (res.status == Response::Successful) {
sprite->body = res.data;
sprite->parseJSON();
body = res.data;
parseJSON();
} else {
Log::Warning(Event::Sprite, "Failed to load sprite info: %s", res.message.c_str());
}
sprite->loadedJSON = true;
sprite->complete();
loadedJSON = true;
complete();
});

env.request({ Resource::Kind::Image, spriteURL }, [sprite](const Response &res) {
spriteRequest = env.request({ Resource::Kind::Image, spriteURL }, [this](const Response &res) {
spriteRequest = nullptr;
if (res.status == Response::Successful) {
sprite->image = res.data;
sprite->parseImage();
image = res.data;
parseImage();
} else {
Log::Warning(Event::Sprite, "Failed to load sprite image: %s", res.message.c_str());
}
sprite->loadedImage = true;
sprite->complete();
loadedImage = true;
complete();
});
}

Sprite::~Sprite() {
if (jsonRequest) {
jsonRequest->cancel();
}

if (spriteRequest) {
spriteRequest->cancel();
}
}

void Sprite::complete() {
if (loadedImage && loadedJSON) {
promise.set_value();
callback();
}
}

bool Sprite::isLoaded() const {
return loadedImage && loadedJSON;
}

void Sprite::waitUntilLoaded() const {
future.wait();
}

bool Sprite::hasPixelRatio(float ratio) const {
return pixelRatio == (ratio > 1 ? 2 : 1);
}

void Sprite::parseImage() {
raster = util::make_unique<util::Image>(image);
if (!*raster) {
Expand Down
25 changes: 8 additions & 17 deletions src/mbgl/map/sprite.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <mbgl/util/image.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/storage/request.hpp>

#include <cstdint>
#include <atomic>
Expand All @@ -15,6 +16,7 @@
namespace mbgl {

class Environment;
class Request;

class SpritePosition {
public:
Expand All @@ -31,15 +33,10 @@ class SpritePosition {
bool sdf = false;
};

class Sprite : public std::enable_shared_from_this<Sprite>, private util::noncopyable {
private:
struct Key {};
void load(Environment &env);

class Sprite : private util::noncopyable {
public:
Sprite(const Key &, const std::string& base_url, float pixelRatio);
static util::ptr<Sprite>
Create(const std::string &base_url, float pixelRatio, Environment &env);
Sprite(const std::string& baseUrl, float pixelRatio, Environment&, std::function<void()> callback);
~Sprite();

const SpritePosition &getSpritePosition(const std::string& name) const;

Expand All @@ -48,23 +45,14 @@ class Sprite : public std::enable_shared_from_this<Sprite>, private util::noncop
void waitUntilLoaded() const;
bool isLoaded() const;

operator bool() const;

private:
const bool valid;

public:
const float pixelRatio;
const std::string spriteURL;
const std::string jsonURL;
std::unique_ptr<util::Image> raster;

private:
void parseJSON();
void parseImage();
void complete();

private:
std::string body;
std::string image;
std::atomic<bool> loadedImage;
Expand All @@ -74,7 +62,10 @@ class Sprite : public std::enable_shared_from_this<Sprite>, private util::noncop

std::promise<void> promise;
std::future<void> future;
std::function<void ()> callback;

Request* jsonRequest = nullptr;
Request* spriteRequest = nullptr;
};

}
Expand Down

0 comments on commit 776612e

Please sign in to comment.