#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { Style::Style(MapData& data_) : data(data_), glyphStore(std::make_unique()), glyphAtlas(std::make_unique(1024, 1024)), spriteStore(std::make_unique(data.pixelRatio)), spriteAtlas(std::make_unique(512, 512, data.pixelRatio, *spriteStore)), lineAtlas(std::make_unique(512, 512)), workers(4) { glyphStore->setObserver(this); spriteStore->setObserver(this); } void Style::setJSON(const std::string& json, const std::string&) { rapidjson::Document doc; doc.Parse<0>((const char *const)json.c_str()); if (doc.HasParseError()) { Log::Error(Event::ParseStyle, "Error parsing style JSON at %i: %s", doc.GetErrorOffset(), rapidjson::GetParseError_En(doc.GetParseError())); return; } StyleParser parser; parser.parse(doc); for (auto& source : parser.sources) { addSource(std::move(source)); } for (auto& layer : parser.layers) { addLayer(std::move(layer)); } glyphStore->setURL(parser.glyphURL); spriteStore->setURL(parser.spriteURL); loaded = true; } Style::~Style() { for (const auto& source : sources) { source->setObserver(nullptr); } glyphStore->setObserver(nullptr); spriteStore->setObserver(nullptr); } void Style::addSource(std::unique_ptr source) { source->setObserver(this); source->load(); sources.emplace_back(std::move(source)); } std::vector> Style::getLayers() const { std::vector> result; result.reserve(layers.size()); for (const auto& layer : layers) { result.push_back(layer->clone()); } return result; } std::vector>::const_iterator Style::findLayer(const std::string& id) const { return std::find_if(layers.begin(), layers.end(), [&](const auto& layer) { return layer->id == id; }); } StyleLayer* Style::getLayer(const std::string& id) const { auto it = findLayer(id); return it != layers.end() ? it->get() : nullptr; } void Style::addLayer(std::unique_ptr layer) { if (SymbolLayer* symbolLayer = dynamic_cast(layer.get())) { if (!symbolLayer->spriteAtlas) { symbolLayer->spriteAtlas = spriteAtlas.get(); } } layers.emplace_back(std::move(layer)); } void Style::addLayer(std::unique_ptr layer, const std::string& before) { layers.emplace(findLayer(before), std::move(layer)); } void Style::removeLayer(const std::string& id) { auto it = findLayer(id); if (it == layers.end()) throw std::runtime_error("no such layer"); layers.erase(it); } void Style::update(const TransformState& transform, TexturePool& texturePool) { bool allTilesUpdated = true; StyleUpdateParameters parameters(data.pixelRatio, data.getDebug(), data.getAnimationTime(), transform, workers, texturePool, shouldReparsePartialTiles, data, *this); for (const auto& source : sources) { if (!source->update(parameters)) { 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() { std::vector classes; std::vector classNames = data.getClasses(); for (auto it = classNames.rbegin(); it != classNames.rend(); it++) { classes.push_back(ClassDictionary::Get().lookup(*it)); } classes.push_back(ClassID::Default); classes.push_back(ClassID::Fallback); StyleCascadeParameters parameters(classes, data.getAnimationTime(), PropertyTransition { data.getDefaultTransitionDuration(), data.getDefaultTransitionDelay() }); for (const auto& layer : layers) { layer->cascade(parameters); } } void Style::recalculate(float z) { std::lock_guard lock(mtx); for (const auto& source : sources) { source->enabled = false; } zoomHistory.update(z, data.getAnimationTime()); StyleCalculationParameters parameters(z, data.getAnimationTime(), zoomHistory, data.getDefaultFadeDuration()); for (const auto& layer : layers) { hasPendingTransitions |= layer->recalculate(parameters); Source* source = getSource(layer->source); if (!source) { continue; } source->enabled = true; } } Source* Style::getSource(const std::string& id) const { const auto it = std::find_if(sources.begin(), sources.end(), [&](const auto& source) { return source->info.source_id == id; }); return it != sources.end() ? it->get() : nullptr; } bool Style::hasTransitions() const { return hasPendingTransitions; } bool Style::isLoaded() const { if (!loaded) { return false; } for (const auto& source : sources) { if (!source->isLoaded()) { return false; } } if (!spriteStore->isLoaded()) { return false; } return true; } void Style::setObserver(Observer* observer_) { assert(util::ThreadContext::currentlyOn(util::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(util::ThreadContext::currentlyOn(util::ThreadType::Map)); if (observer) { observer->onTileDataChanged(); } } void Style::emitResourceLoadingFailed(std::exception_ptr error) { assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); try { if (error) { lastError = error; std::rethrow_exception(error); } } catch(const std::exception& e) { Log::Error(Event::Style, "%s", e.what()); } if (observer) { observer->onResourceLoadingFailed(error); } } void Style::dumpDebugLogs() const { for (const auto& source : sources) { source->dumpDebugLogs(); } spriteStore->dumpDebugLogs(); } }