[core] Split style image collection from SpriteAtlas

This commit is contained in:
Ivo van Dongen
2017-05-12 23:19:00 +03:00
committed by John Firebaugh
parent c80f3e9d29
commit cc9f040a2d
33 changed files with 677 additions and 413 deletions

View File

@@ -4,6 +4,7 @@
#include <mbgl/annotation/symbol_annotation_impl.hpp>
#include <mbgl/annotation/line_annotation_impl.hpp>
#include <mbgl/annotation/fill_annotation_impl.hpp>
#include <mbgl/sprite/sprite_image_collection.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
@@ -19,7 +20,7 @@ const std::string AnnotationManager::SourceID = "com.mapbox.annotations";
const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points";
AnnotationManager::AnnotationManager(float pixelRatio)
: spriteAtlas({ 1024, 1024 }, pixelRatio) {
: spriteAtlas({ 1024, 1024 }, pixelRatio){
// This is a special atlas, holding only images added via addIcon, so we always treat it as
// loaded.
spriteAtlas.markAsLoaded();
@@ -190,16 +191,20 @@ void AnnotationManager::removeTile(AnnotationTile& tile) {
}
void AnnotationManager::addImage(const std::string& id, std::unique_ptr<style::Image> image) {
spriteAtlas.addImage(id, std::move(image));
addSpriteImage(spriteImages, id, std::move(image), [&](style::Image& added) {
spriteAtlas.addImage(id, std::make_unique<style::Image>(added));
});
}
void AnnotationManager::removeImage(const std::string& id) {
spriteAtlas.removeImage(id);
removeSpriteImage(spriteImages, id, [&] () {
spriteAtlas.removeImage(id);
});
}
double AnnotationManager::getTopOffsetPixelsForImage(const std::string& id) {
const style::Image* image = spriteAtlas.getImage(id);
return image ? -(image->image.size.height / image->pixelRatio) / 2 : 0;
return image ? -(image->getImage().size.height / image->getPixelRatio()) / 2 : 0;
}
} // namespace mbgl

View File

@@ -9,6 +9,7 @@
#include <string>
#include <vector>
#include <unordered_set>
#include <unordered_map>
namespace mbgl {
@@ -72,6 +73,8 @@ private:
ShapeAnnotationMap shapeAnnotations;
std::unordered_set<std::string> obsoleteShapeAnnotationLayers;
std::unordered_set<AnnotationTile*> tiles;
std::unordered_map<std::string, std::unique_ptr<style::Image>> spriteImages;
SpriteAtlas spriteAtlas;
friend class AnnotationTile;

View File

@@ -942,8 +942,7 @@ void Map::addImage(const std::string& id, std::unique_ptr<style::Image> image) {
}
impl->styleMutated = true;
impl->style->spriteAtlas->addImage(id, std::move(image));
impl->onUpdate(Update::Repaint);
impl->style->addImage(id, std::move(image));
}
void Map::removeImage(const std::string& id) {
@@ -952,13 +951,12 @@ void Map::removeImage(const std::string& id) {
}
impl->styleMutated = true;
impl->style->spriteAtlas->removeImage(id);
impl->onUpdate(Update::Repaint);
impl->style->removeImage(id);
}
const style::Image* Map::getImage(const std::string& id) {
if (impl->style) {
return impl->style->spriteAtlas->getImage(id);
return impl->style->getImage(id);
}
return nullptr;
}

View File

@@ -1,7 +1,4 @@
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/sprite/sprite_atlas_worker.hpp>
#include <mbgl/sprite/sprite_atlas_observer.hpp>
#include <mbgl/sprite/sprite_parser.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/platform.hpp>
@@ -9,11 +6,6 @@
#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 <mbgl/util/run_loop.hpp>
#include <mbgl/actor/actor.hpp>
#include <cassert>
#include <cmath>
@@ -21,28 +13,12 @@
namespace mbgl {
static SpriteAtlasObserver nullObserver;
struct SpriteAtlas::Loader {
Loader(Scheduler& scheduler, SpriteAtlas& spriteAtlas)
: mailbox(std::make_shared<Mailbox>(*util::RunLoop::Get())),
worker(scheduler, ActorRef<SpriteAtlas>(spriteAtlas, mailbox)) {
}
std::shared_ptr<const std::string> image;
std::shared_ptr<const std::string> json;
std::unique_ptr<AsyncRequest> jsonRequest;
std::unique_ptr<AsyncRequest> spriteRequest;
std::shared_ptr<Mailbox> mailbox;
Actor<SpriteAtlasWorker> worker;
};
SpriteAtlasElement::SpriteAtlasElement(Rect<uint16_t> rect_,
const style::Image& image,
Size size_, float pixelRatio)
: pos(std::move(rect_)),
sdf(image.sdf),
relativePixelRatio(image.pixelRatio / pixelRatio),
sdf(image.isSdf()),
relativePixelRatio(image.getPixelRatio() / pixelRatio),
width(image.getWidth()),
height(image.getHeight()) {
@@ -59,87 +35,25 @@ SpriteAtlasElement::SpriteAtlasElement(Rect<uint16_t> rect_,
SpriteAtlas::SpriteAtlas(Size size_, float pixelRatio_)
: size(std::move(size_)),
pixelRatio(pixelRatio_),
observer(&nullObserver),
bin(size.width, size.height),
dirty(true) {
}
SpriteAtlas::~SpriteAtlas() = default;
void SpriteAtlas::load(const std::string& url, Scheduler& scheduler, FileSource& fileSource) {
if (url.empty()) {
// Treat a non-existent sprite as a successfully loaded empty sprite.
markAsLoaded();
return;
}
loader = std::make_unique<Loader>(scheduler, *this);
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;
}
loader->worker.invoke(&SpriteAtlasWorker::parse, loader->image, loader->json);
// TODO: delete the loader?
}
void SpriteAtlas::onParsed(Images&& result) {
void SpriteAtlas::onSpriteLoaded(Images&& result) {
markAsLoaded();
for (auto& pair : result) {
addImage(pair.first, std::move(pair.second));
}
observer->onSpriteLoaded();
for (auto requestor : requestors) {
requestor->onIconsAvailable(buildIconMap());
}
requestors.clear();
}
void SpriteAtlas::onError(std::exception_ptr err) {
observer->onSpriteError(err);
}
void SpriteAtlas::setObserver(SpriteAtlasObserver* observer_) {
observer = observer_;
}
void SpriteAtlas::dumpDebugLogs() const {
Log::Info(Event::General, "SpriteAtlas::loaded: %d", loaded);
}
void SpriteAtlas::addImage(const std::string& id, std::unique_ptr<style::Image> image_) {
icons.clear();
@@ -152,10 +66,7 @@ void SpriteAtlas::addImage(const std::string& id, std::unique_ptr<style::Image>
Entry& entry = it->second;
// There is already a sprite with that name in our store.
if (entry.image->image.size != image_->image.size) {
Log::Warning(Event::Sprite, "Can't change sprite dimensions for '%s'", id.c_str());
return;
}
assert(entry.image->getImage().size == image_->getImage().size);
entry.image = std::move(image_);
@@ -172,9 +83,7 @@ void SpriteAtlas::removeImage(const std::string& id) {
icons.clear();
auto it = entries.find(id);
if (it == entries.end()) {
return;
}
assert(it != entries.end());
Entry& entry = it->second;
@@ -243,8 +152,8 @@ optional<SpriteAtlasElement> SpriteAtlas::getImage(const std::string& id,
};
}
const uint16_t pixelWidth = std::ceil(entry.image->image.size.width / pixelRatio);
const uint16_t pixelHeight = std::ceil(entry.image->image.size.height / pixelRatio);
const uint16_t pixelWidth = std::ceil(entry.image->getImage().size.width / pixelRatio);
const uint16_t pixelHeight = std::ceil(entry.image->getImage().size.height / pixelRatio);
// Increase to next number divisible by 4, but at least 1.
// This is so we can scale down the texture coordinates and pack them
@@ -279,7 +188,7 @@ void SpriteAtlas::copy(const Entry& entry, optional<Rect<uint16_t>> Entry::*entr
image.fill(0);
}
const PremultipliedImage& src = entry.image->image;
const PremultipliedImage& src = entry.image->getImage();
const Rect<uint16_t>& rect = *(entry.*entryRect);
const uint32_t padding = 1;
@@ -337,4 +246,8 @@ void SpriteAtlas::bind(bool linear, gl::Context& context, gl::TextureUnit unit)
linear ? gl::TextureFilter::Linear : gl::TextureFilter::Nearest);
}
void SpriteAtlas::dumpDebugLogs() const {
Log::Info(Event::General, "SpriteAtlas::loaded: %d", loaded);
}
} // namespace mbgl

View File

@@ -7,7 +7,6 @@
#include <mbgl/style/image.hpp>
#include <string>
#include <map>
#include <set>
#include <unordered_map>
#include <array>
@@ -15,10 +14,6 @@
namespace mbgl {
class Scheduler;
class FileSource;
class SpriteAtlasObserver;
namespace gl {
class Context;
} // namespace gl
@@ -38,7 +33,7 @@ public:
float height;
};
using IconMap = std::map<std::string, SpriteAtlasElement>;
using IconMap = std::unordered_map<std::string, SpriteAtlasElement>;
using IconDependencies = std::set<std::string>;
class IconRequestor {
@@ -48,12 +43,12 @@ public:
class SpriteAtlas : public util::noncopyable {
public:
using Images = std::map<std::string, std::unique_ptr<style::Image>>;
using Images = std::unordered_map<std::string, std::unique_ptr<style::Image>>;
SpriteAtlas(Size, float pixelRatio);
~SpriteAtlas();
void load(const std::string& url, Scheduler&, FileSource&);
void onSpriteLoaded(Images&&);
void markAsLoaded() {
loaded = true;
@@ -65,8 +60,6 @@ public:
void dumpDebugLogs() const;
void setObserver(SpriteAtlasObserver*);
const style::Image* getImage(const std::string&) const;
void addImage(const std::string&, std::unique_ptr<style::Image>);
void removeImage(const std::string&);
@@ -93,25 +86,12 @@ public:
}
private:
void emitSpriteLoadedIfComplete();
// Invoked by SpriteAtlasWorker
friend class SpriteAtlasWorker;
void onParsed(Images&& result);
void onError(std::exception_ptr);
const Size size;
const float pixelRatio;
struct Loader;
std::unique_ptr<Loader> loader;
bool loaded = false;
SpriteAtlasObserver* observer = nullptr;
struct Entry {
std::unique_ptr<style::Image> image;
std::unique_ptr<const style::Image> image;
// One sprite image might be used as both an icon image and a pattern image. If so,
// it must have two distinct entries in the texture. The one for the icon image has

View File

@@ -1,15 +0,0 @@
#pragma once
#include <exception>
namespace mbgl {
class SpriteAtlasObserver {
public:
virtual ~SpriteAtlasObserver() = default;
virtual void onSpriteLoaded() {}
virtual void onSpriteError(std::exception_ptr) {}
};
} // namespace mbgl

View File

@@ -0,0 +1,40 @@
#include <mbgl/sprite/sprite_image_collection.hpp>
#include <mbgl/util/logging.hpp>
namespace mbgl {
void addSpriteImage(Images& images, const std::string& id,
std::unique_ptr<style::Image> image_,
std::function<void (style::Image&)> onAdded) {
auto it = images.find(id);
if (it == images.end()) {
// Add new
it = images.emplace(id, std::move(image_)).first;
onAdded(*it->second.get());
return;
}
std::unique_ptr<style::Image>& image = it->second;
// There is already a sprite with that name in our store.
if (image->getImage().size != image_->getImage().size) {
Log::Warning(Event::Sprite, "Can't change sprite dimensions for '%s'", id.c_str());
}
// Update existing
image = std::move(image_);
onAdded(*it->second.get());
}
void removeSpriteImage(Images& images,
const std::string& id,
std::function<void ()> onRemoved) {
if (images.erase(id) > 0) {
onRemoved();
}
}
} // namespace mbgl

View File

@@ -0,0 +1,25 @@
#pragma once
#include <mbgl/style/image.hpp>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
namespace mbgl {
using Images = std::unordered_map<std::string, std::unique_ptr<style::Image>>;
void addSpriteImage(Images&,
const std::string&,
std::unique_ptr<style::Image>,
std::function<void (style::Image&)> onAdded = [] (style::Image&){});
void removeSpriteImage(Images&,
const std::string&,
std::function<void ()> onRemoved = [] (){});
} // namespace mbgl

View File

@@ -0,0 +1,107 @@
#include <mbgl/sprite/sprite_loader.hpp>
#include <mbgl/sprite/sprite_loader_worker.hpp>
#include <mbgl/sprite/sprite_loader_observer.hpp>
#include <mbgl/sprite/sprite_parser.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/platform.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 <mbgl/util/run_loop.hpp>
#include <mbgl/actor/actor.hpp>
#include <cassert>
namespace mbgl {
static SpriteLoaderObserver nullObserver;
struct SpriteLoader::Loader {
Loader(Scheduler& scheduler, SpriteLoader& spriteAtlas)
: mailbox(std::make_shared<Mailbox>(*util::RunLoop::Get())),
worker(scheduler, ActorRef<SpriteLoader>(spriteAtlas, mailbox)) {
}
std::shared_ptr<const std::string> image;
std::shared_ptr<const std::string> json;
std::unique_ptr<AsyncRequest> jsonRequest;
std::unique_ptr<AsyncRequest> spriteRequest;
std::shared_ptr<Mailbox> mailbox;
Actor<SpriteLoaderWorker> worker;
};
SpriteLoader::SpriteLoader(float pixelRatio_)
: pixelRatio(pixelRatio_)
, observer(&nullObserver) {
}
SpriteLoader::~SpriteLoader() = default;
void SpriteLoader::load(const std::string& url, Scheduler& scheduler, FileSource& fileSource) {
if (url.empty()) {
// Treat a non-existent sprite as a successfully loaded empty sprite.
observer->onSpriteLoaded({});
return;
}
loader = std::make_unique<Loader>(scheduler, *this);
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 SpriteLoader::emitSpriteLoadedIfComplete() {
assert(loader);
if (!loader->image || !loader->json) {
return;
}
loader->worker.invoke(&SpriteLoaderWorker::parse, loader->image, loader->json);
}
void SpriteLoader::onParsed(Images&& result) {
observer->onSpriteLoaded(std::move(result));
}
void SpriteLoader::onError(std::exception_ptr err) {
observer->onSpriteError(err);
}
void SpriteLoader::setObserver(SpriteLoaderObserver* observer_) {
observer = observer_;
}
} // namespace mbgl

View File

@@ -0,0 +1,46 @@
#pragma once
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/style/image.hpp>
#include <string>
#include <map>
#include <set>
#include <unordered_map>
#include <array>
#include <memory>
namespace mbgl {
class Scheduler;
class FileSource;
class SpriteLoaderObserver;
class SpriteLoader : public util::noncopyable {
public:
using Images = std::unordered_map<std::string, std::unique_ptr<style::Image>>;
SpriteLoader(float pixelRatio);
~SpriteLoader();
void load(const std::string& url, Scheduler&, FileSource&);
void setObserver(SpriteLoaderObserver*);
private:
void emitSpriteLoadedIfComplete();
// Invoked by SpriteAtlasWorker
friend class SpriteLoaderWorker;
void onParsed(Images&& result);
void onError(std::exception_ptr);
const float pixelRatio;
struct Loader;
std::unique_ptr<Loader> loader;
SpriteLoaderObserver* observer = nullptr;
};
} // namespace mbgl

View File

@@ -0,0 +1,24 @@
#pragma once
#include <exception>
#include <memory>
#include <unordered_map>
#include <string>
namespace mbgl {
namespace style {
class Image;
} // namespace style
class SpriteLoaderObserver {
public:
using Images = std::unordered_map<std::string, std::unique_ptr<style::Image>>;
virtual ~SpriteLoaderObserver() = default;
virtual void onSpriteLoaded(Images&&) {}
virtual void onSpriteError(std::exception_ptr) {}
};
} // namespace mbgl

View File

@@ -1,14 +1,14 @@
#include <mbgl/sprite/sprite_atlas_worker.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/sprite/sprite_loader_worker.hpp>
#include <mbgl/sprite/sprite_loader.hpp>
#include <mbgl/sprite/sprite_parser.hpp>
namespace mbgl {
SpriteAtlasWorker::SpriteAtlasWorker(ActorRef<SpriteAtlasWorker>, ActorRef<SpriteAtlas> parent_)
SpriteLoaderWorker::SpriteLoaderWorker(ActorRef<SpriteLoaderWorker>, ActorRef<SpriteLoader> parent_)
: parent(std::move(parent_)) {
}
void SpriteAtlasWorker::parse(std::shared_ptr<const std::string> image,
void SpriteLoaderWorker::parse(std::shared_ptr<const std::string> image,
std::shared_ptr<const std::string> json) {
try {
if (!image) {
@@ -20,9 +20,9 @@ void SpriteAtlasWorker::parse(std::shared_ptr<const std::string> image,
throw std::runtime_error("missing sprite metadata");
}
parent.invoke(&SpriteAtlas::onParsed, parseSprite(*image, *json));
parent.invoke(&SpriteLoader::onParsed, parseSprite(*image, *json));
} catch (...) {
parent.invoke(&SpriteAtlas::onError, std::current_exception());
parent.invoke(&SpriteLoader::onError, std::current_exception());
}
}

View File

@@ -8,16 +8,16 @@
namespace mbgl {
class SpriteAtlas;
class SpriteLoader;
class SpriteAtlasWorker {
class SpriteLoaderWorker {
public:
SpriteAtlasWorker(ActorRef<SpriteAtlasWorker>, ActorRef<SpriteAtlas>);
SpriteLoaderWorker(ActorRef<SpriteLoaderWorker>, ActorRef<SpriteLoader>);
void parse(std::shared_ptr<const std::string> image, std::shared_ptr<const std::string> json);
private:
ActorRef<SpriteAtlas> parent;
ActorRef<SpriteLoader> parent;
};
} // namespace mbgl

View File

@@ -7,7 +7,7 @@
#include <string>
#include <memory>
#include <map>
#include <unordered_map>
namespace mbgl {
@@ -24,7 +24,7 @@ std::unique_ptr<style::Image> createStyleImage(const PremultipliedImage&,
double ratio,
bool sdf);
using Images = std::map<std::string, std::unique_ptr<style::Image>>;
using Images = std::unordered_map<std::string, std::unique_ptr<style::Image>>;
// Parses an image and an associated JSON file and returns the sprite objects.
Images parseSprite(const std::string& image, const std::string& json);

View File

@@ -1,21 +1,35 @@
#include <mbgl/style/image.hpp>
#include <mbgl/style/image_impl.hpp>
#include <mbgl/util/exception.hpp>
namespace mbgl {
namespace style {
Image::Image(PremultipliedImage&& image_,
const float pixelRatio_,
bool sdf_)
: image(std::move(image_)),
pixelRatio(pixelRatio_),
sdf(sdf_) {
Image::Image(PremultipliedImage &&image,
const float pixelRatio,
bool sdf)
: impl(std::make_shared<Impl>(std::move(image), pixelRatio, sdf)) {
}
if (!image.valid()) {
throw util::SpriteImageException("Sprite image dimensions may not be zero");
} else if (pixelRatio <= 0) {
throw util::SpriteImageException("Sprite pixelRatio may not be <= 0");
}
PremultipliedImage& Image::getImage() const {
assert(impl);
return impl->image;
}
bool Image::isSdf() const {
return impl->sdf;
}
float Image::getPixelRatio() const {
return impl->pixelRatio;
}
float Image::getWidth() const {
return impl->getWidth();
}
float Image::getHeight() const {
return impl->getHeight();
}
} // namespace style

View File

@@ -0,0 +1,22 @@
#include <mbgl/style/image_impl.hpp>
#include <mbgl/util/exception.hpp>
namespace mbgl {
namespace style {
Image::Impl::Impl(PremultipliedImage&& image_,
const float pixelRatio_,
bool sdf_)
: image(std::move(image_)),
pixelRatio(pixelRatio_),
sdf(sdf_) {
if (!image.valid()) {
throw util::SpriteImageException("Sprite image dimensions may not be zero");
} else if (pixelRatio <= 0) {
throw util::SpriteImageException("Sprite pixelRatio may not be <= 0");
}
}
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,25 @@
#pragma once
#include <mbgl/style/image.hpp>
namespace mbgl {
namespace style {
class Image::Impl {
public:
Impl(PremultipliedImage&&, float pixelRatio, bool sdf = false);
PremultipliedImage image;
// Pixel ratio of the sprite image.
const float pixelRatio;
// Whether this image should be interpreted as a signed distance field icon.
const bool sdf;
float getWidth() const { return image.size.width / pixelRatio; }
float getHeight() const { return image.size.height / pixelRatio; }
};
} // namespace style
} // namespace mbgl

View File

@@ -1,6 +1,5 @@
#pragma once
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>

View File

@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/text/glyph_atlas_observer.hpp>
#include <mbgl/sprite/sprite_atlas_observer.hpp>
#include <mbgl/sprite/sprite_loader_observer.hpp>
#include <mbgl/style/source_observer.hpp>
#include <mbgl/map/update.hpp>
@@ -11,7 +11,7 @@ namespace mbgl {
namespace style {
class Observer : public GlyphAtlasObserver,
public SpriteAtlasObserver,
public SpriteLoaderObserver,
public SourceObserver {
public:
virtual void onUpdate(Update) {}

View File

@@ -17,6 +17,8 @@
#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/class_dictionary.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/sprite/sprite_image_collection.hpp>
#include <mbgl/sprite/sprite_loader.hpp>
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/renderer/update_parameters.hpp>
@@ -72,13 +74,14 @@ Style::Style(Scheduler& scheduler_, FileSource& fileSource_, float pixelRatio)
: scheduler(scheduler_),
fileSource(fileSource_),
glyphAtlas(std::make_unique<GlyphAtlas>(Size{ 2048, 2048 }, fileSource)),
spriteLoader(std::make_unique<SpriteLoader>(pixelRatio)),
spriteAtlas(std::make_unique<SpriteAtlas>(Size{ 1024, 1024 }, pixelRatio)),
lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })),
light(std::make_unique<Light>()),
renderLight(light->impl),
observer(&nullObserver) {
glyphAtlas->setObserver(this);
spriteAtlas->setObserver(this);
spriteLoader->setObserver(this);
light->setObserver(this);
}
@@ -160,7 +163,7 @@ void Style::setJSON(const std::string& json) {
setLight(std::make_unique<Light>(parser.light));
glyphAtlas->setURL(parser.glyphURL);
spriteAtlas->load(parser.spriteURL, scheduler, fileSource);
spriteLoader->load(parser.spriteURL, scheduler, fileSource);
loaded = true;
@@ -539,6 +542,24 @@ bool Style::isLoaded() const {
return true;
}
void Style::addImage(const std::string& id, std::unique_ptr<style::Image> image) {
addSpriteImage(spriteImages, id, std::move(image), [&](style::Image& added) {
spriteAtlas->addImage(id, std::make_unique<style::Image>(added));
observer->onUpdate(Update::Repaint);
});
}
void Style::removeImage(const std::string& id) {
removeSpriteImage(spriteImages, id, [&] () {
spriteAtlas->removeImage(id);
observer->onUpdate(Update::Repaint);
});
}
const style::Image* Style::getImage(const std::string& id) const {
return spriteAtlas->getImage(id);
}
RenderData Style::getRenderData(MapDebugOptions debugOptions, float angle) const {
RenderData result;
@@ -755,8 +776,20 @@ void Style::onTileError(RenderSource& source, const OverscaledTileID& tileID, st
observer->onResourceError(error);
}
void Style::onSpriteLoaded() {
observer->onSpriteLoaded();
void Style::onSpriteLoaded(SpriteLoader::Images&& images) {
// Add images to collection
Images addedImages;
for (auto& entry : images) {
addSpriteImage(spriteImages, entry.first, std::move(entry.second), [&] (style::Image& added) {
addedImages.emplace(entry.first, std::make_unique<Image>(added));
});
}
// Update render sprite atlas
spriteAtlas->onSpriteLoaded(std::move(addedImages));
// Update observer
observer->onSpriteLoaded(std::move(images));
observer->onUpdate(Update::Repaint); // For *-pattern properties.
}

View File

@@ -11,7 +11,7 @@
#include <mbgl/renderer/render_layer.hpp>
#include <mbgl/renderer/render_light.hpp>
#include <mbgl/text/glyph_atlas_observer.hpp>
#include <mbgl/sprite/sprite_atlas_observer.hpp>
#include <mbgl/sprite/sprite_loader_observer.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/map/zoom_history.hpp>
@@ -31,6 +31,7 @@ namespace mbgl {
class FileSource;
class GlyphAtlas;
class SpriteAtlas;
class SpriteLoader;
class LineAtlas;
class RenderData;
class TransformState;
@@ -44,7 +45,7 @@ class Layer;
class QueryParameters;
class Style : public GlyphAtlasObserver,
public SpriteAtlasObserver,
public SpriteLoaderObserver,
public SourceObserver,
public RenderSourceObserver,
public LayerObserver,
@@ -106,6 +107,10 @@ public:
Light* getLight() const;
const RenderLight& getRenderLight() const;
const style::Image* getImage(const std::string&) const;
void addImage(const std::string&, std::unique_ptr<style::Image>);
void removeImage(const std::string&);
RenderData getRenderData(MapDebugOptions, float angle) const;
std::vector<Feature> queryRenderedFeatures(const ScreenLineString& geometry,
@@ -120,6 +125,7 @@ public:
Scheduler& scheduler;
FileSource& fileSource;
std::unique_ptr<GlyphAtlas> glyphAtlas;
std::unique_ptr<SpriteLoader> spriteLoader;
std::unique_ptr<SpriteAtlas> spriteAtlas;
std::unique_ptr<LineAtlas> lineAtlas;
@@ -152,8 +158,9 @@ private:
void onGlyphsLoaded(const FontStack&, const GlyphRange&) override;
void onGlyphsError(const FontStack&, const GlyphRange&, std::exception_ptr) override;
// SpriteStoreObserver implementation.
void onSpriteLoaded() override;
// SpriteLoaderObserver implementation.
std::unordered_map<std::string, std::unique_ptr<style::Image>> spriteImages;
void onSpriteLoaded(SpriteLoaderObserver::Images&&) override;
void onSpriteError(std::exception_ptr) override;
// SourceObserver implementation.