Merge ResourceLoader into Style and move atlas ownership

This commit is contained in:
John Firebaugh
2015-05-28 13:50:47 -07:00
parent d2f7105649
commit ec06bb7e3c
13 changed files with 256 additions and 389 deletions

View File

@@ -2,19 +2,12 @@
#include <mbgl/map/map_data.hpp>
#include <mbgl/map/view.hpp>
#include <mbgl/map/environment.hpp>
#include <mbgl/map/source.hpp>
#include <mbgl/map/still_image.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/text/glyph_store.hpp>
#include <mbgl/geometry/glyph_atlas.hpp>
#include <mbgl/geometry/sprite_atlas.hpp>
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
@@ -34,10 +27,6 @@ MapContext::MapContext(uv_loop_t* loop, View& view_, FileSource& fileSource, Map
envScope(env, ThreadType::Map, "Map"),
updated(static_cast<UpdateType>(Update::Nothing)),
asyncUpdate(std::make_unique<uv::async>(loop, [this] { update(); })),
glyphStore(std::make_unique<GlyphStore>(loop, env)),
glyphAtlas(std::make_unique<GlyphAtlas>(1024, 1024)),
spriteAtlas(std::make_unique<SpriteAtlas>(512, 512)),
lineAtlas(std::make_unique<LineAtlas>(512, 512)),
texturePool(std::make_unique<TexturePool>()) {
assert(Environment::currentlyOn(ThreadType::Map));
@@ -51,14 +40,9 @@ MapContext::~MapContext() {
// Explicit resets currently necessary because these abandon resources that need to be
// cleaned up by env.performCleanup();
resourceLoader.reset();
style.reset();
painter.reset();
texturePool.reset();
lineAtlas.reset();
spriteAtlas.reset();
glyphAtlas.reset();
glyphStore.reset();
env.performCleanup();
@@ -116,21 +100,11 @@ void MapContext::setStyleJSON(const std::string& json, const std::string& base)
void MapContext::loadStyleJSON(const std::string& json, const std::string& base) {
assert(Environment::currentlyOn(ThreadType::Map));
resourceLoader.reset();
style.reset();
style = std::make_unique<Style>();
style->base = base;
style->loadJSON((const uint8_t *)json.c_str());
style = std::make_unique<Style>(json, base, asyncUpdate->get()->loop, env);
style->cascade(data.getClasses());
style->setDefaultTransitionDuration(data.getDefaultTransitionDuration());
glyphStore->setURL(style->glyph_url);
resourceLoader = std::make_unique<ResourceLoader>();
resourceLoader->setObserver(this);
resourceLoader->setStyle(style.get());
resourceLoader->setGlyphStore(glyphStore.get());
style->setObserver(this);
triggerUpdate(Update::Zoom);
}
@@ -138,7 +112,7 @@ void MapContext::loadStyleJSON(const std::string& json, const std::string& base)
void MapContext::updateTiles() {
assert(Environment::currentlyOn(ThreadType::Map));
resourceLoader->update(data, transformState, *glyphAtlas, *spriteAtlas, *texturePool);
style->update(data, transformState, *texturePool);
}
void MapContext::updateAnnotationTiles(const std::vector<TileID>& ids) {
@@ -177,7 +151,7 @@ void MapContext::update() {
updateTiles();
if (style->isLoaded() && resourceLoader->getSprite()->isLoaded()) {
if (style->isLoaded()) {
if (!data.getFullyLoaded()) {
data.setFullyLoaded(true);
}
@@ -220,7 +194,7 @@ void MapContext::render() {
assert(style);
if (!painter) {
painter = std::make_unique<Painter>(*spriteAtlas, *glyphAtlas, *lineAtlas);
painter = std::make_unique<Painter>();
painter->setup();
}
@@ -240,7 +214,7 @@ void MapContext::render() {
double MapContext::getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol) {
assert(Environment::currentlyOn(ThreadType::Map));
const SpritePosition pos = resourceLoader->getSprite()->getSpritePosition(symbol);
const SpritePosition pos = style->sprite->getSpritePosition(symbol);
return -pos.height / pos.pixelRatio / 2;
}

View File

@@ -4,8 +4,8 @@
#include <mbgl/map/tile_id.hpp>
#include <mbgl/map/update.hpp>
#include <mbgl/map/environment.hpp>
#include <mbgl/map/resource_loader.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/util/ptr.hpp>
#include <vector>
@@ -20,20 +20,15 @@ namespace mbgl {
class View;
class MapData;
class GlyphStore;
class GlyphAtlas;
class SpriteAtlas;
class LineAtlas;
class TexturePool;
class Painter;
class Sprite;
class Style;
class Worker;
class StillImage;
struct LatLng;
struct LatLngBounds;
class MapContext : public ResourceLoader::Observer {
class MapContext : public Style::Observer {
public:
MapContext(uv_loop_t*, View&, FileSource&, MapData&);
~MapContext();
@@ -81,14 +76,9 @@ private:
UpdateType updated { static_cast<UpdateType>(Update::Nothing) };
std::unique_ptr<uv::async> asyncUpdate;
std::unique_ptr<GlyphStore> glyphStore;
std::unique_ptr<GlyphAtlas> glyphAtlas;
std::unique_ptr<SpriteAtlas> spriteAtlas;
std::unique_ptr<LineAtlas> lineAtlas;
std::unique_ptr<TexturePool> texturePool;
std::unique_ptr<Painter> painter;
std::unique_ptr<Style> style;
std::unique_ptr<ResourceLoader> resourceLoader;
std::string styleURL;
std::string styleJSON;

View File

@@ -1,160 +0,0 @@
#include <mbgl/map/resource_loader.hpp>
#include <mbgl/geometry/sprite_atlas.hpp>
#include <mbgl/map/environment.hpp>
#include <mbgl/map/source.hpp>
#include <mbgl/map/sprite.hpp>
#include <mbgl/map/transform.hpp>
#include <mbgl/style/style.hpp>
#include <cassert>
namespace mbgl {
ResourceLoader::ResourceLoader() {
assert(Environment::currentlyOn(ThreadType::Map));
}
ResourceLoader::~ResourceLoader() {
assert(Environment::currentlyOn(ThreadType::Map));
for (const auto& source : style_->sources) {
source->setObserver(nullptr);
}
if (sprite_) {
sprite_->setObserver(nullptr);
}
if (glyphStore_) {
glyphStore_->setObserver(nullptr);
}
}
void ResourceLoader::setObserver(Observer* observer) {
assert(Environment::currentlyOn(ThreadType::Map));
assert(!observer_);
observer_ = observer;
}
void ResourceLoader::setStyle(Style* style) {
assert(style);
style_ = style;
for (const auto& source : style->sources) {
source->setObserver(this);
source->load();
}
}
void ResourceLoader::setGlyphStore(GlyphStore* glyphStore) {
assert(glyphStore);
if (glyphStore_) {
glyphStore_->setObserver(nullptr);
}
glyphStore_ = glyphStore;
glyphStore_->setObserver(this);
}
void ResourceLoader::update(MapData& data,
const TransformState& transform,
GlyphAtlas& glyphAtlas,
SpriteAtlas& spriteAtlas,
TexturePool& texturePool) {
if (!style_) {
return;
}
const float pixelRatio = transform.getPixelRatio();
if (!sprite_ || !sprite_->hasPixelRatio(pixelRatio)) {
sprite_ = std::make_unique<Sprite>(style_->getSpriteURL(), pixelRatio);
sprite_->setObserver(this);
spriteAtlas.resize(pixelRatio);
spriteAtlas.setSprite(sprite_);
}
bool allTilesUpdated = true;
for (const auto& source : style_->sources) {
if (!source->update(data, transform, *style_, glyphAtlas, *glyphStore_,
spriteAtlas, sprite_, texturePool, shouldReparsePartialTiles_)) {
allTilesUpdated = false;
}
}
// We can only stop updating "partial" tiles when all of them
// were notified of the arrival of the new resources.
if (allTilesUpdated) {
shouldReparsePartialTiles_ = false;
}
}
void ResourceLoader::onGlyphRangeLoaded() {
shouldReparsePartialTiles_ = true;
emitTileDataChanged();
}
void ResourceLoader::onGlyphRangeLoadingFailed(std::exception_ptr error) {
emitResourceLoadingFailed(error);
}
void ResourceLoader::onSourceLoaded() {
emitTileDataChanged();
}
void ResourceLoader::onSourceLoadingFailed(std::exception_ptr error) {
emitResourceLoadingFailed(error);
}
void ResourceLoader::onTileLoaded(bool isNewTile) {
if (isNewTile) {
shouldReparsePartialTiles_ = true;
}
emitTileDataChanged();
}
void ResourceLoader::onTileLoadingFailed(std::exception_ptr error) {
emitResourceLoadingFailed(error);
}
void ResourceLoader::onSpriteLoaded() {
shouldReparsePartialTiles_ = true;
emitTileDataChanged();
}
void ResourceLoader::onSpriteLoadingFailed(std::exception_ptr error) {
emitResourceLoadingFailed(error);
}
void ResourceLoader::emitTileDataChanged() {
assert(Environment::currentlyOn(ThreadType::Map));
if (observer_) {
observer_->onTileDataChanged();
}
}
void ResourceLoader::emitResourceLoadingFailed(std::exception_ptr error) {
assert(Environment::currentlyOn(ThreadType::Map));
try {
if (error) {
std::rethrow_exception(error);
}
} catch(const std::exception& e) {
Log::Error(Event::ResourceLoader, e.what());
}
if (observer_) {
observer_->onResourceLoadingFailed(error);
}
}
}

View File

@@ -1,91 +0,0 @@
#ifndef MBGL_MAP_RESOURCE_LOADER
#define MBGL_MAP_RESOURCE_LOADER
#include <mbgl/map/source.hpp>
#include <mbgl/map/sprite.hpp>
#include <mbgl/text/glyph_store.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <string>
namespace mbgl {
class GlyphAtlas;
class GlyphStore;
class MapData;
class SpriteAtlas;
class Style;
class TexturePool;
class TransformState;
// ResourceLoader is responsible for loading and updating the Source(s) owned
// by the Style. The Source object currently owns all the tiles, thus this
// class will notify its observers of any change on these tiles which will
// ultimately cause a new rendering to be triggered.
class ResourceLoader : public GlyphStore::Observer,
public Source::Observer,
public Sprite::Observer,
private util::noncopyable {
public:
class Observer {
public:
virtual ~Observer() = default;
virtual void onTileDataChanged() = 0;
virtual void onResourceLoadingFailed(std::exception_ptr error) = 0;
};
ResourceLoader();
~ResourceLoader();
void setObserver(Observer* observer);
// The style object currently owns all the sources. When setting
// a new style we will go through all of them and try to load.
void setStyle(Style* style);
// TODO: Move GlyphStore to ResourceLoader. We cannot do it now
// because we reset the ResourceLoader every time we change the
// style.
void setGlyphStore(GlyphStore* glyphStore);
// Fetch the tiles needed by the current viewport and emit a signal when
// a tile is ready so observers can render the tile.
void update(MapData&, const TransformState&, GlyphAtlas&, SpriteAtlas&, TexturePool&);
// FIXME: There is probably a better place for this.
inline util::ptr<Sprite> getSprite() const {
return sprite_;
}
// GlyphStore::Observer implementation.
void onGlyphRangeLoaded() override;
void onGlyphRangeLoadingFailed(std::exception_ptr error) override;
// Source::Observer implementation.
void onSourceLoaded() override;
void onSourceLoadingFailed(std::exception_ptr error) override;
void onTileLoaded(bool isNewTile) override;
void onTileLoadingFailed(std::exception_ptr error) override;
// Sprite::Observer implementation.
void onSpriteLoaded() override;
void onSpriteLoadingFailed(std::exception_ptr error) override;
private:
void emitTileDataChanged();
void emitResourceLoadingFailed(std::exception_ptr error);
bool shouldReparsePartialTiles_ = false;
util::ptr<Sprite> sprite_;
GlyphStore* glyphStore_ = nullptr;
Style* style_ = nullptr;
Observer* observer_ = nullptr;
};
}
#endif

View File

@@ -41,11 +41,7 @@ using namespace mbgl;
#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
Painter::Painter(SpriteAtlas& spriteAtlas_, GlyphAtlas& glyphAtlas_, LineAtlas& lineAtlas_)
: spriteAtlas(spriteAtlas_)
, glyphAtlas(glyphAtlas_)
, lineAtlas(lineAtlas_)
{
Painter::Painter() {
}
Painter::~Painter() {
@@ -171,6 +167,10 @@ void Painter::prepareTile(const Tile& tile) {
void Painter::render(const Style& style, TransformState state_, TimePoint time) {
state = state_;
glyphAtlas = style.glyphAtlas.get();
spriteAtlas = style.spriteAtlas.get();
lineAtlas = style.lineAtlas.get();
std::set<Source*> sources;
for (const auto& source : style.sources) {
if (source->enabled) {
@@ -191,9 +191,9 @@ void Painter::render(const Style& style, TransformState state_, TimePoint time)
tileStencilBuffer.upload();
tileBorderBuffer.upload();
spriteAtlas.upload();
lineAtlas.upload();
glyphAtlas.upload();
spriteAtlas->upload();
lineAtlas->upload();
glyphAtlas->upload();
for (const auto& item : order) {
if (item.bucket && item.bucket->needsUpload()) {
@@ -389,8 +389,8 @@ void Painter::renderBackground(const StyleLayer &layer_desc) {
if ((properties.opacity >= 1.0f) != (pass == RenderPass::Opaque))
return;
SpriteAtlasPosition imagePosA = spriteAtlas.getPosition(properties.image.from, true);
SpriteAtlasPosition imagePosB = spriteAtlas.getPosition(properties.image.to, true);
SpriteAtlasPosition imagePosA = spriteAtlas->getPosition(properties.image.from, true);
SpriteAtlasPosition imagePosB = spriteAtlas->getPosition(properties.image.to, true);
float zoomFraction = state.getZoomFraction();
useProgram(patternShader->program);
@@ -439,7 +439,7 @@ void Painter::renderBackground(const StyleLayer &layer_desc) {
backgroundBuffer.bind();
patternShader->bind(0);
spriteAtlas.bind(true);
spriteAtlas->bind(true);
} else {
Color color = properties.color;
color[0] *= properties.opacity;

View File

@@ -78,7 +78,7 @@ struct RenderItem {
class Painter : private util::noncopyable {
public:
Painter(SpriteAtlas&, GlyphAtlas&, LineAtlas&);
Painter();
~Painter();
void setup();
@@ -204,9 +204,9 @@ private:
public:
FrameHistory frameHistory;
SpriteAtlas& spriteAtlas;
GlyphAtlas& glyphAtlas;
LineAtlas& lineAtlas;
SpriteAtlas* spriteAtlas;
GlyphAtlas* glyphAtlas;
LineAtlas* lineAtlas;
std::unique_ptr<PlainShader> plainShader;
std::unique_ptr<OutlineShader> outlineShader;

View File

@@ -63,8 +63,8 @@ void Painter::renderFill(FillBucket& bucket, const StyleLayer &layer_desc, const
// Image fill.
if (pass == RenderPass::Translucent) {
const SpriteAtlasPosition posA = spriteAtlas.getPosition(properties.image.from, true);
const SpriteAtlasPosition posB = spriteAtlas.getPosition(properties.image.to, true);
const SpriteAtlasPosition posA = spriteAtlas->getPosition(properties.image.from, true);
const SpriteAtlasPosition posB = spriteAtlas->getPosition(properties.image.to, true);
float factor = 8.0 / std::pow(2, state.getIntegerZoom() - id.z);
mat3 patternMatrixA;
@@ -91,7 +91,7 @@ void Painter::renderFill(FillBucket& bucket, const StyleLayer &layer_desc, const
patternShader->u_patternmatrix_b = patternMatrixB;
MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0));
spriteAtlas.bind(true);
spriteAtlas->bind(true);
// Draw the actual triangles into the color & stencil buffer.
config.depthMask = GL_TRUE;

View File

@@ -66,9 +66,9 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const
linesdfShader->u_blur = blur;
linesdfShader->u_color = color;
LinePatternPos posA = lineAtlas.getDashPosition(properties.dash_array.from, layout.cap == CapType::Round);
LinePatternPos posB = lineAtlas.getDashPosition(properties.dash_array.to, layout.cap == CapType::Round);
lineAtlas.bind();
LinePatternPos posA = lineAtlas->getDashPosition(properties.dash_array.from, layout.cap == CapType::Round);
LinePatternPos posB = lineAtlas->getDashPosition(properties.dash_array.to, layout.cap == CapType::Round);
lineAtlas->bind();
float patternratio = std::pow(2.0, std::floor(std::log2(state.getScale())) - id.z) / 8.0;
float scaleXA = patternratio / posA.width / properties.dash_line_width / properties.dash_array.fromScale;
@@ -81,14 +81,14 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const
linesdfShader->u_patternscale_b = {{ scaleXB, scaleYB }};
linesdfShader->u_tex_y_b = posB.y;
linesdfShader->u_image = 0;
linesdfShader->u_sdfgamma = lineAtlas.width / (properties.dash_line_width * std::min(posA.width, posB.width) * 256.0 * state.getPixelRatio()) / 2;
linesdfShader->u_sdfgamma = lineAtlas->width / (properties.dash_line_width * std::min(posA.width, posB.width) * 256.0 * state.getPixelRatio()) / 2;
linesdfShader->u_mix = properties.dash_array.t;
bucket.drawLineSDF(*linesdfShader);
} else if (properties.image.from.size()) {
SpriteAtlasPosition imagePosA = spriteAtlas.getPosition(properties.image.from, true);
SpriteAtlasPosition imagePosB = spriteAtlas.getPosition(properties.image.to, true);
SpriteAtlasPosition imagePosA = spriteAtlas->getPosition(properties.image.from, true);
SpriteAtlasPosition imagePosB = spriteAtlas->getPosition(properties.image.to, true);
float factor = 8.0 / std::pow(2, state.getIntegerZoom() - id.z);
@@ -110,7 +110,7 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const
linepatternShader->u_opacity = properties.opacity;
MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0));
spriteAtlas.bind(true);
spriteAtlas->bind(true);
config.depthRange = { strata + strata_epsilon, 1.0f }; // may or may not matter
bucket.drawLinePatterns(*linepatternShader);

View File

@@ -138,7 +138,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c
const float fontSize = properties.icon.size != 0 ? properties.icon.size : layout.icon.max_size;
const float fontScale = fontSize / 1.0f;
spriteAtlas.bind(state.isChanging() || layout.placement == PlacementType::Line || angleOffset != 0 || fontScale != 1 || sdf);
spriteAtlas->bind(state.isChanging() || layout.placement == PlacementType::Line || angleOffset != 0 || fontScale != 1 || sdf);
if (sdf) {
renderSDF(bucket,
@@ -147,7 +147,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c
layout.icon,
properties.icon,
1.0f,
{{ float(spriteAtlas.getWidth()) / 4.0f, float(spriteAtlas.getHeight()) / 4.0f }},
{{ float(spriteAtlas->getWidth()) / 4.0f, float(spriteAtlas->getHeight()) / 4.0f }},
*sdfIconShader,
&SymbolBucket::drawIcons);
} else {
@@ -165,7 +165,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c
useProgram(iconShader->program);
iconShader->u_matrix = vtxMatrix;
iconShader->u_exmatrix = exMatrix;
iconShader->u_texsize = {{ float(spriteAtlas.getWidth()) / 4.0f, float(spriteAtlas.getHeight()) / 4.0f }};
iconShader->u_texsize = {{ float(spriteAtlas->getWidth()) / 4.0f, float(spriteAtlas->getHeight()) / 4.0f }};
// Convert the -pi..pi to an int8 range.
const float angle = std::round(state.getAngle() / M_PI * 128);
@@ -192,7 +192,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c
}
if (bucket.hasTextData()) {
glyphAtlas.bind();
glyphAtlas->bind();
renderSDF(bucket,
id,
@@ -200,7 +200,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c
layout.text,
properties.text,
24.0f,
{{ float(glyphAtlas.width) / 4, float(glyphAtlas.height) / 4 }},
{{ float(glyphAtlas->width) / 4, float(glyphAtlas->height) / 4 }},
*sdfGlyphShader,
&SymbolBucket::drawGlyphs);
}

View File

@@ -1,9 +1,13 @@
#include <mbgl/style/style.hpp>
#include <mbgl/map/sprite.hpp>
#include <mbgl/map/source.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_parser.hpp>
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/geometry/glyph_atlas.hpp>
#include <mbgl/geometry/sprite_atlas.hpp>
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/uv_detail.hpp>
#include <mbgl/platform/log.hpp>
@@ -15,15 +19,79 @@
namespace mbgl {
Style::Style()
: mtx(std::make_unique<uv::rwlock>()),
Style::Style(const std::string& data, const std::string& base_,
uv_loop_t* loop, Environment& env)
: glyphStore(std::make_unique<GlyphStore>(loop, env)),
glyphAtlas(std::make_unique<GlyphAtlas>(1024, 1024)),
spriteAtlas(std::make_unique<SpriteAtlas>(512, 512)),
lineAtlas(std::make_unique<LineAtlas>(512, 512)),
base(base_),
mtx(std::make_unique<uv::rwlock>()),
workers(4) {
rapidjson::Document doc;
doc.Parse<0>((const char *const)data.c_str());
if (doc.HasParseError()) {
Log::Error(Event::ParseStyle, "Error parsing style JSON at %i: %s", doc.GetErrorOffset(), doc.GetParseError());
return;
}
StyleParser parser;
parser.parse(doc);
sources = parser.getSources();
layers = parser.getLayers();
sprite_url = parser.getSprite();
glyph_url = parser.getGlyphURL();
glyphStore->setURL(glyph_url);
for (const auto& source : sources) {
source->setObserver(this);
source->load();
}
glyphStore->setObserver(this);
}
// Note: This constructor is seemingly empty, but we need to declare it anyway
// because this file includes uv_detail.hpp, which has the declarations necessary
// for deleting the std::unique_ptr<uv::rwlock>.
Style::~Style() {}
Style::~Style() {
for (const auto& source : sources) {
source->setObserver(nullptr);
}
glyphStore->setObserver(nullptr);
if (sprite) {
sprite->setObserver(nullptr);
}
}
void Style::update(MapData& data,
const TransformState& transform,
TexturePool& texturePool) {
const float pixelRatio = transform.getPixelRatio();
if (!sprite || !sprite->hasPixelRatio(pixelRatio)) {
sprite = std::make_unique<Sprite>(sprite_url, pixelRatio);
sprite->setObserver(this);
spriteAtlas->resize(pixelRatio);
spriteAtlas->setSprite(sprite);
}
bool allTilesUpdated = true;
for (const auto& source : sources) {
if (!source->update(data, transform, *this, *glyphAtlas, *glyphStore,
*spriteAtlas, sprite, texturePool, shouldReparsePartialTiles)) {
allTilesUpdated = false;
}
}
// We can only stop updating "partial" tiles when all of them
// were notified of the arrival of the new resources.
if (allTilesUpdated) {
shouldReparsePartialTiles = false;
}
}
void Style::cascade(const std::vector<std::string>& classes) {
TimePoint now = Clock::now();
@@ -50,10 +118,6 @@ void Style::recalculate(float z, TimePoint now) {
}
}
const std::string &Style::getSpriteURL() const {
return sprite_url;
}
void Style::setDefaultTransitionDuration(Duration duration) {
defaultTransition.duration = duration;
}
@@ -67,44 +131,89 @@ bool Style::hasTransitions() const {
return false;
}
void Style::loadJSON(const uint8_t *const data) {
uv::writelock lock(mtx);
rapidjson::Document doc;
doc.Parse<0>((const char *const)data);
if (doc.HasParseError()) {
Log::Error(Event::ParseStyle, "Error parsing style JSON at %i: %s", doc.GetErrorOffset(), doc.GetParseError());
return;
}
StyleParser parser;
parser.parse(doc);
sources = parser.getSources();
layers = parser.getLayers();
sprite_url = parser.getSprite();
glyph_url = parser.getGlyphURL();
loaded = true;
}
bool Style::isLoaded() const {
// TODO: move loading into Style
if (!loaded) {
return false;
}
for (const auto& source : sources) {
if (!source->isLoaded()) {
return false;
}
}
// TODO: move sprite into Style
// if (sprite && !sprite.isLoaded()) {
// return false;
// }
if (sprite && !sprite->isLoaded()) {
return false;
}
return true;
}
void Style::setObserver(Observer* observer_) {
assert(Environment::currentlyOn(ThreadType::Map));
assert(!observer);
observer = observer_;
}
void Style::onGlyphRangeLoaded() {
shouldReparsePartialTiles = true;
emitTileDataChanged();
}
void Style::onGlyphRangeLoadingFailed(std::exception_ptr error) {
emitResourceLoadingFailed(error);
}
void Style::onSourceLoaded() {
emitTileDataChanged();
}
void Style::onSourceLoadingFailed(std::exception_ptr error) {
emitResourceLoadingFailed(error);
}
void Style::onTileLoaded(bool isNewTile) {
if (isNewTile) {
shouldReparsePartialTiles = true;
}
emitTileDataChanged();
}
void Style::onTileLoadingFailed(std::exception_ptr error) {
emitResourceLoadingFailed(error);
}
void Style::onSpriteLoaded() {
shouldReparsePartialTiles = true;
emitTileDataChanged();
}
void Style::onSpriteLoadingFailed(std::exception_ptr error) {
emitResourceLoadingFailed(error);
}
void Style::emitTileDataChanged() {
assert(Environment::currentlyOn(ThreadType::Map));
if (observer) {
observer->onTileDataChanged();
}
}
void Style::emitResourceLoadingFailed(std::exception_ptr error) {
assert(Environment::currentlyOn(ThreadType::Map));
try {
if (error) {
std::rethrow_exception(error);
}
} catch(const std::exception& e) {
Log::Error(Event::ResourceLoader, e.what());
}
if (observer) {
observer->onResourceLoadingFailed(error);
}
}
}

View File

@@ -4,6 +4,10 @@
#include <mbgl/style/property_transition.hpp>
#include <mbgl/style/zoom_history.hpp>
#include <mbgl/map/source.hpp>
#include <mbgl/map/sprite.hpp>
#include <mbgl/text/glyph_store.hpp>
#include <mbgl/util/uv.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/util/noncopyable.hpp>
@@ -16,33 +20,79 @@
namespace mbgl {
class Source;
class Environment;
class GlyphAtlas;
class GlyphStore;
class SpriteAtlas;
class LineAtlas;
class StyleLayer;
class Style : public util::noncopyable {
class Style : public GlyphStore::Observer,
public Source::Observer,
public Sprite::Observer,
public util::noncopyable {
public:
Style();
Style(const std::string& data,
const std::string& base,
uv_loop_t*, Environment&);
~Style();
void loadJSON(const uint8_t *const data);
class Observer {
public:
virtual ~Observer() = default;
virtual void onTileDataChanged() = 0;
virtual void onResourceLoadingFailed(std::exception_ptr error) = 0;
};
void setObserver(Observer*);
bool isLoaded() const;
// Fetch the tiles needed by the current viewport and emit a signal when
// a tile is ready so observers can render the tile.
void update(MapData&, const TransformState&, TexturePool&);
void cascade(const std::vector<std::string>&);
void recalculate(float z, TimePoint now);
void setDefaultTransitionDuration(Duration);
bool hasTransitions() const;
const std::string &getSpriteURL() const;
std::unique_ptr<GlyphStore> glyphStore;
std::unique_ptr<GlyphAtlas> glyphAtlas;
util::ptr<Sprite> sprite;
std::unique_ptr<SpriteAtlas> spriteAtlas;
std::unique_ptr<LineAtlas> lineAtlas;
std::vector<util::ptr<Source>> sources;
std::vector<util::ptr<StyleLayer>> layers;
std::string glyph_url;
std::string base;
private:
bool loaded = false;
// GlyphStore::Observer implementation.
void onGlyphRangeLoaded() override;
void onGlyphRangeLoadingFailed(std::exception_ptr error) override;
// Source::Observer implementation.
void onSourceLoaded() override;
void onSourceLoadingFailed(std::exception_ptr error) override;
void onTileLoaded(bool isNewTile) override;
void onTileLoadingFailed(std::exception_ptr error) override;
// Sprite::Observer implementation.
void onSpriteLoaded() override;
void onSpriteLoadingFailed(std::exception_ptr error) override;
void emitTileDataChanged();
void emitResourceLoadingFailed(std::exception_ptr error);
bool shouldReparsePartialTiles = false;
Observer* observer = nullptr;
std::string base;
std::string sprite_url;
std::string glyph_url;
PropertyTransition defaultTransition;
std::unique_ptr<uv::rwlock> mtx;
ZoomHistory zoomHistory;

View File

@@ -1,6 +1,6 @@
#include "../fixtures/util.hpp"
#include <mbgl/style/style.hpp>
#include <mbgl/style/style_parser.hpp>
#include <mbgl/util/io.hpp>
#include <rapidjson/document.h>
@@ -22,27 +22,23 @@ class StyleParserTest : public ::testing::TestWithParam<std::string> {};
TEST_P(StyleParserTest, ParseStyle) {
const std::string &base = "test/fixtures/style_parser/" + GetParam();
const std::string style_path = base + ".style.json";
const std::string info = util::read_file(base + ".info.json");
rapidjson::Document infoDoc;
infoDoc.Parse<0>(util::read_file(base + ".info.json").c_str());
ASSERT_FALSE(infoDoc.HasParseError());
ASSERT_TRUE(infoDoc.IsObject());
// Parse settings.
rapidjson::Document doc;
doc.Parse<0>((const char *const)info.c_str());
ASSERT_FALSE(doc.HasParseError());
ASSERT_TRUE(doc.IsObject());
std::ifstream stylefile(style_path);
ASSERT_TRUE(stylefile.good());
std::stringstream stylejson;
stylejson << stylefile.rdbuf();
rapidjson::Document styleDoc;
styleDoc.Parse<0>(util::read_file(base + ".style.json").c_str());
ASSERT_FALSE(styleDoc.HasParseError());
ASSERT_TRUE(styleDoc.IsObject());
FixtureLogObserver* observer = new FixtureLogObserver();
Log::setObserver(std::unique_ptr<Log::Observer>(observer));
Style style;
style.loadJSON((const uint8_t *)stylejson.str().c_str());
StyleParser parser;
parser.parse(styleDoc);
for (auto it = doc.MemberBegin(), end = doc.MemberEnd(); it != end; it++) {
for (auto it = infoDoc.MemberBegin(), end = infoDoc.MemberEnd(); it != end; it++) {
const std::string name { it->name.GetString(), it->name.GetStringLength() };
const rapidjson::Value &value = it->value;
ASSERT_EQ(true, value.IsObject());

View File

@@ -62,7 +62,6 @@
'resources/mock_file_source.cpp',
'resources/mock_file_source.hpp',
'resources/mock_view.hpp',
'resources/resource_loader.cpp',
'storage/storage.hpp',
'storage/storage.cpp',