[core] Convert MapContext to Map::Impl; eliminate indirection
This commit is contained in:
@@ -8,7 +8,6 @@
|
||||
#include <mbgl/map/mode.hpp>
|
||||
#include <mbgl/util/geo.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/vec.hpp>
|
||||
#include <mbgl/annotation/annotation.hpp>
|
||||
#include <mbgl/style/types.hpp>
|
||||
#include <mbgl/style/property_transition.hpp>
|
||||
@@ -23,18 +22,13 @@ namespace mbgl {
|
||||
|
||||
class FileSource;
|
||||
class View;
|
||||
class MapData;
|
||||
class MapContext;
|
||||
class SpriteImage;
|
||||
class Transform;
|
||||
class PointAnnotation;
|
||||
class ShapeAnnotation;
|
||||
struct CameraOptions;
|
||||
struct AnimationOptions;
|
||||
|
||||
class Map : private util::noncopyable {
|
||||
friend class View;
|
||||
|
||||
public:
|
||||
explicit Map(View&, FileSource&,
|
||||
MapMode mapMode = MapMode::Continuous,
|
||||
@@ -176,19 +170,8 @@ public:
|
||||
void dumpDebugLogs() const;
|
||||
|
||||
private:
|
||||
View& view;
|
||||
const std::unique_ptr<Transform> transform;
|
||||
const std::unique_ptr<MapContext> context;
|
||||
MapData* data;
|
||||
|
||||
enum class RenderState {
|
||||
never,
|
||||
partial,
|
||||
fully
|
||||
};
|
||||
|
||||
RenderState renderState = RenderState::never;
|
||||
bool loading = false;
|
||||
class Impl;
|
||||
const std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/map/map_context.hpp>
|
||||
#include <mbgl/map/camera.hpp>
|
||||
#include <mbgl/map/view.hpp>
|
||||
#include <mbgl/map/transform.hpp>
|
||||
@@ -7,57 +6,179 @@
|
||||
#include <mbgl/map/map_data.hpp>
|
||||
#include <mbgl/annotation/point_annotation.hpp>
|
||||
#include <mbgl/annotation/shape_annotation.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/style/style_layer.hpp>
|
||||
#include <mbgl/style/property_transition.hpp>
|
||||
#include <mbgl/layer/custom_layer.hpp>
|
||||
|
||||
#include <mbgl/renderer/painter.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/storage/resource.hpp>
|
||||
#include <mbgl/storage/response.hpp>
|
||||
#include <mbgl/gl/gl_object_store.hpp>
|
||||
#include <mbgl/gl/texture_pool.hpp>
|
||||
#include <mbgl/util/projection.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
#include <mbgl/util/exception.hpp>
|
||||
#include <mbgl/util/async_task.hpp>
|
||||
#include <mbgl/util/mapbox.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
Map::Map(View& view_, FileSource& fileSource, MapMode mapMode, GLContextMode contextMode, ConstrainMode constrainMode)
|
||||
: view(view_),
|
||||
transform(std::make_unique<Transform>(view, constrainMode)),
|
||||
context(std::make_unique<MapContext>(
|
||||
view, fileSource, mapMode, contextMode, view.getPixelRatio())),
|
||||
data(&context->getData())
|
||||
{
|
||||
enum class RenderState {
|
||||
never,
|
||||
partial,
|
||||
fully
|
||||
};
|
||||
|
||||
class Map::Impl : public Style::Observer {
|
||||
public:
|
||||
Impl(View&, FileSource&, MapMode, GLContextMode, ConstrainMode);
|
||||
|
||||
void onResourceLoaded() override;
|
||||
void onResourceError(std::exception_ptr) override;
|
||||
|
||||
void update();
|
||||
void render();
|
||||
|
||||
void loadStyleJSON(const std::string& json, const std::string& base);
|
||||
|
||||
View& view;
|
||||
FileSource& fileSource;
|
||||
|
||||
RenderState renderState = RenderState::never;
|
||||
Transform transform;
|
||||
|
||||
std::unique_ptr<MapData> dataPtr;
|
||||
MapData& data;
|
||||
|
||||
gl::GLObjectStore glObjectStore;
|
||||
Update updateFlags = Update::Nothing;
|
||||
util::AsyncTask asyncUpdate;
|
||||
|
||||
std::unique_ptr<gl::TexturePool> texturePool;
|
||||
std::unique_ptr<Painter> painter;
|
||||
std::unique_ptr<Style> style;
|
||||
|
||||
std::string styleURL;
|
||||
std::string styleJSON;
|
||||
|
||||
std::unique_ptr<AsyncRequest> styleRequest;
|
||||
|
||||
Map::StillImageCallback callback;
|
||||
size_t sourceCacheSize;
|
||||
TransformState transformState;
|
||||
FrameData frameData;
|
||||
bool loading = false;
|
||||
};
|
||||
|
||||
Map::Map(View& view, FileSource& fileSource, MapMode mapMode, GLContextMode contextMode, ConstrainMode constrainMode)
|
||||
: impl(std::make_unique<Impl>(view, fileSource, mapMode, contextMode, constrainMode)) {
|
||||
view.initialize(this);
|
||||
update(Update::Dimensions);
|
||||
}
|
||||
|
||||
Map::Impl::Impl(View& view_, FileSource& fileSource_, MapMode mode_, GLContextMode contextMode_, ConstrainMode constrainMode_)
|
||||
: view(view_),
|
||||
fileSource(fileSource_),
|
||||
transform(view, constrainMode_),
|
||||
dataPtr(std::make_unique<MapData>(mode_, contextMode_, view_.getPixelRatio())),
|
||||
data(*dataPtr),
|
||||
asyncUpdate([this] { update(); }),
|
||||
texturePool(std::make_unique<gl::TexturePool>()) {
|
||||
}
|
||||
|
||||
Map::~Map() {
|
||||
context->cleanup();
|
||||
impl->view.activate();
|
||||
|
||||
impl->styleRequest = nullptr;
|
||||
|
||||
// Explicit resets currently necessary because these abandon resources that need to be
|
||||
// cleaned up by glObjectStore.performCleanup();
|
||||
impl->style.reset();
|
||||
impl->painter.reset();
|
||||
impl->texturePool.reset();
|
||||
impl->dataPtr.reset();
|
||||
|
||||
impl->glObjectStore.performCleanup();
|
||||
|
||||
impl->view.deactivate();
|
||||
}
|
||||
|
||||
void Map::renderStill(StillImageCallback callback) {
|
||||
context->renderStill(transform->getState(),
|
||||
FrameData { view.getFramebufferSize(), Clock::now() }, callback);
|
||||
if (!callback) {
|
||||
Log::Error(Event::General, "StillImageCallback not set");
|
||||
return;
|
||||
}
|
||||
|
||||
if (impl->data.mode != MapMode::Still) {
|
||||
callback(std::make_exception_ptr(util::MisuseException("Map is not in still image render mode")), {});
|
||||
return;
|
||||
}
|
||||
|
||||
if (impl->callback) {
|
||||
callback(std::make_exception_ptr(util::MisuseException("Map is currently rendering an image")), {});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!impl->style) {
|
||||
callback(std::make_exception_ptr(util::MisuseException("Map doesn't have a style")), {});
|
||||
return;
|
||||
}
|
||||
|
||||
if (impl->style->getLastError()) {
|
||||
callback(impl->style->getLastError(), {});
|
||||
return;
|
||||
}
|
||||
|
||||
impl->callback = callback;
|
||||
impl->transformState = impl->transform.getState();
|
||||
impl->frameData = FrameData{ impl->view.getFramebufferSize(), Clock::now() };
|
||||
|
||||
impl->updateFlags |= Update::RenderStill;
|
||||
impl->asyncUpdate.send();
|
||||
}
|
||||
|
||||
void Map::update(Update flags) {
|
||||
if (flags & Update::Dimensions) {
|
||||
impl->transform.resize(impl->view.getSize());
|
||||
}
|
||||
|
||||
impl->transformState = impl->transform.getState();
|
||||
impl->updateFlags |= flags;
|
||||
|
||||
impl->asyncUpdate.send();
|
||||
}
|
||||
|
||||
void Map::render() {
|
||||
if (renderState == RenderState::never) {
|
||||
view.notifyMapChange(MapChangeWillStartRenderingMap);
|
||||
if (!impl->style) {
|
||||
return;
|
||||
}
|
||||
|
||||
view.notifyMapChange(MapChangeWillStartRenderingFrame);
|
||||
if (impl->renderState == RenderState::never) {
|
||||
impl->view.notifyMapChange(MapChangeWillStartRenderingMap);
|
||||
}
|
||||
|
||||
const Update flags = transform->updateTransitions(Clock::now());
|
||||
const bool fullyLoaded = context->renderSync(transform->getState(), FrameData { view.getFramebufferSize(), Clock::now() });
|
||||
impl->view.notifyMapChange(MapChangeWillStartRenderingFrame);
|
||||
|
||||
view.notifyMapChange(fullyLoaded ?
|
||||
const Update flags = impl->transform.updateTransitions(Clock::now());
|
||||
|
||||
impl->transformState = impl->transform.getState();
|
||||
impl->frameData = FrameData { impl->view.getFramebufferSize(), Clock::now() };
|
||||
|
||||
impl->render();
|
||||
|
||||
impl->view.notifyMapChange(isFullyLoaded() ?
|
||||
MapChangeDidFinishRenderingFrameFullyRendered :
|
||||
MapChangeDidFinishRenderingFrame);
|
||||
|
||||
if (!fullyLoaded) {
|
||||
renderState = RenderState::partial;
|
||||
} else if (renderState != RenderState::fully) {
|
||||
renderState = RenderState::fully;
|
||||
view.notifyMapChange(MapChangeDidFinishRenderingMapFullyRendered);
|
||||
if (loading) {
|
||||
loading = false;
|
||||
view.notifyMapChange(MapChangeDidFinishLoadingMap);
|
||||
if (!isFullyLoaded()) {
|
||||
impl->renderState = RenderState::partial;
|
||||
} else if (impl->renderState != RenderState::fully) {
|
||||
impl->renderState = RenderState::fully;
|
||||
impl->view.notifyMapChange(MapChangeDidFinishRenderingMapFullyRendered);
|
||||
if (impl->loading) {
|
||||
impl->loading = false;
|
||||
impl->view.notifyMapChange(MapChangeDidFinishLoadingMap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,83 +189,195 @@ void Map::render() {
|
||||
}
|
||||
}
|
||||
|
||||
void Map::update(Update flags) {
|
||||
if (flags & Update::Dimensions) transform->resize(view.getSize());
|
||||
context->triggerUpdate(transform->getState(), flags);
|
||||
void Map::Impl::update() {
|
||||
if (!style) {
|
||||
updateFlags = Update::Nothing;
|
||||
}
|
||||
|
||||
if (updateFlags == Update::Nothing || (data.mode == MapMode::Still && !callback)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This time point is used to:
|
||||
// - Calculate style property transitions;
|
||||
// - Hint style sources to notify when all its tiles are loaded;
|
||||
frameData.timePoint = Clock::now();
|
||||
|
||||
if (style->loaded && updateFlags & Update::Annotations) {
|
||||
data.getAnnotationManager()->updateStyle(*style);
|
||||
updateFlags |= Update::Classes;
|
||||
}
|
||||
|
||||
if (updateFlags & Update::Classes) {
|
||||
style->cascade(frameData.timePoint);
|
||||
}
|
||||
|
||||
if (updateFlags & Update::Classes || updateFlags & Update::RecalculateStyle) {
|
||||
style->recalculate(transformState.getZoom(), frameData.timePoint);
|
||||
}
|
||||
|
||||
style->update(transformState, frameData.timePoint, *texturePool);
|
||||
|
||||
if (data.mode == MapMode::Continuous) {
|
||||
view.invalidate();
|
||||
} else if (callback && style->isLoaded()) {
|
||||
view.activate();
|
||||
render();
|
||||
view.deactivate();
|
||||
}
|
||||
|
||||
updateFlags = Update::Nothing;
|
||||
}
|
||||
|
||||
void Map::Impl::render() {
|
||||
if (!painter) {
|
||||
painter = std::make_unique<Painter>(data, transformState, glObjectStore);
|
||||
}
|
||||
|
||||
painter->render(*style,
|
||||
frameData,
|
||||
data.getAnnotationManager()->getSpriteAtlas());
|
||||
|
||||
if (data.mode == MapMode::Still) {
|
||||
callback(nullptr, view.readStillImage());
|
||||
callback = nullptr;
|
||||
}
|
||||
|
||||
glObjectStore.performCleanup();
|
||||
|
||||
if (style->hasTransitions()) {
|
||||
updateFlags |= Update::RecalculateStyle;
|
||||
asyncUpdate.send();
|
||||
} else if (painter->needsAnimation()) {
|
||||
updateFlags |= Update::Repaint;
|
||||
asyncUpdate.send();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Style
|
||||
|
||||
void Map::setStyleURL(const std::string &url) {
|
||||
loading = true;
|
||||
view.notifyMapChange(MapChangeWillStartLoadingMap);
|
||||
context->setStyleURL(url);
|
||||
void Map::setStyleURL(const std::string& url) {
|
||||
if (impl->styleURL == url) {
|
||||
return;
|
||||
}
|
||||
|
||||
impl->loading = true;
|
||||
|
||||
impl->view.notifyMapChange(MapChangeWillStartLoadingMap);
|
||||
|
||||
impl->styleRequest = nullptr;
|
||||
impl->styleURL = url;
|
||||
impl->styleJSON.clear();
|
||||
|
||||
impl->style = std::make_unique<Style>(impl->data, impl->fileSource);
|
||||
|
||||
const size_t pos = impl->styleURL.rfind('/');
|
||||
std::string base = "";
|
||||
if (pos != std::string::npos) {
|
||||
base = impl->styleURL.substr(0, pos + 1);
|
||||
}
|
||||
|
||||
impl->styleRequest = impl->fileSource.request(Resource::style(impl->styleURL), [this, base](Response res) {
|
||||
if (res.error) {
|
||||
if (res.error->reason == Response::Error::Reason::NotFound &&
|
||||
util::mapbox::isMapboxURL(impl->styleURL)) {
|
||||
Log::Error(Event::Setup, "style %s could not be found or is an incompatible legacy map or style", impl->styleURL.c_str());
|
||||
} else {
|
||||
Log::Error(Event::Setup, "loading style failed: %s", res.error->message.c_str());
|
||||
}
|
||||
} else if (res.notModified || res.noContent) {
|
||||
return;
|
||||
} else {
|
||||
impl->loadStyleJSON(*res.data, base);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Map::setStyleJSON(const std::string& json, const std::string& base) {
|
||||
loading = true;
|
||||
view.notifyMapChange(MapChangeWillStartLoadingMap);
|
||||
context->setStyleJSON(json, base);
|
||||
if (impl->styleJSON == json) {
|
||||
return;
|
||||
}
|
||||
|
||||
impl->loading = true;
|
||||
|
||||
impl->view.notifyMapChange(MapChangeWillStartLoadingMap);
|
||||
|
||||
impl->styleURL.clear();
|
||||
impl->styleJSON.clear();
|
||||
impl->style = std::make_unique<Style>(impl->data, impl->fileSource);
|
||||
|
||||
impl->loadStyleJSON(json, base);
|
||||
}
|
||||
|
||||
void Map::Impl::loadStyleJSON(const std::string& json, const std::string& base) {
|
||||
style->setJSON(json, base);
|
||||
style->setObserver(this);
|
||||
styleJSON = json;
|
||||
|
||||
// force style cascade, causing all pending transitions to complete.
|
||||
style->cascade(Clock::now());
|
||||
|
||||
updateFlags |= Update::Classes | Update::RecalculateStyle | Update::Annotations;
|
||||
asyncUpdate.send();
|
||||
}
|
||||
|
||||
std::string Map::getStyleURL() const {
|
||||
return context->getStyleURL();
|
||||
return impl->styleURL;
|
||||
}
|
||||
|
||||
std::string Map::getStyleJSON() const {
|
||||
return context->getStyleJSON();
|
||||
return impl->styleJSON;
|
||||
}
|
||||
|
||||
#pragma mark - Transitions
|
||||
|
||||
void Map::cancelTransitions() {
|
||||
transform->cancelTransitions();
|
||||
impl->transform.cancelTransitions();
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
void Map::setGestureInProgress(bool inProgress) {
|
||||
transform->setGestureInProgress(inProgress);
|
||||
impl->transform.setGestureInProgress(inProgress);
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
bool Map::isGestureInProgress() const {
|
||||
return transform->isGestureInProgress();
|
||||
return impl->transform.isGestureInProgress();
|
||||
}
|
||||
|
||||
bool Map::isRotating() const {
|
||||
return transform->isRotating();
|
||||
return impl->transform.isRotating();
|
||||
}
|
||||
|
||||
bool Map::isScaling() const {
|
||||
return transform->isScaling();
|
||||
return impl->transform.isScaling();
|
||||
}
|
||||
|
||||
bool Map::isPanning() const {
|
||||
return transform->isPanning();
|
||||
return impl->transform.isPanning();
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
void Map::jumpTo(const CameraOptions& camera) {
|
||||
transform->jumpTo(camera);
|
||||
impl->transform.jumpTo(camera);
|
||||
update(camera.zoom ? Update::RecalculateStyle : Update::Repaint);
|
||||
}
|
||||
|
||||
void Map::easeTo(const CameraOptions& camera, const AnimationOptions& animation) {
|
||||
transform->easeTo(camera, animation);
|
||||
impl->transform.easeTo(camera, animation);
|
||||
update(camera.zoom ? Update::RecalculateStyle : Update::Repaint);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Map::flyTo(const CameraOptions& camera, const AnimationOptions& animation) {
|
||||
transform->flyTo(camera, animation);
|
||||
impl->transform.flyTo(camera, animation);
|
||||
update(Update::RecalculateStyle);
|
||||
}
|
||||
|
||||
#pragma mark - Position
|
||||
|
||||
void Map::moveBy(const ScreenCoordinate& point, const Duration& duration) {
|
||||
transform->moveBy(point, duration);
|
||||
impl->transform.moveBy(point, duration);
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
@@ -153,17 +386,17 @@ void Map::setLatLng(const LatLng& latLng, const Duration& duration) {
|
||||
}
|
||||
|
||||
void Map::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const Duration& duration) {
|
||||
transform->setLatLng(latLng, padding, duration);
|
||||
impl->transform.setLatLng(latLng, padding, duration);
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
void Map::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const Duration& duration) {
|
||||
transform->setLatLng(latLng, anchor, duration);
|
||||
impl->transform.setLatLng(latLng, anchor, duration);
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
LatLng Map::getLatLng(optional<EdgeInsets> padding) const {
|
||||
return transform->getLatLng(padding);
|
||||
return impl->transform.getLatLng(padding);
|
||||
}
|
||||
|
||||
void Map::resetPosition(optional<EdgeInsets> padding) {
|
||||
@@ -173,7 +406,7 @@ void Map::resetPosition(optional<EdgeInsets> padding) {
|
||||
camera.center = LatLng(0, 0);
|
||||
camera.padding = padding;
|
||||
camera.zoom = 0;
|
||||
transform->jumpTo(camera);
|
||||
impl->transform.jumpTo(camera);
|
||||
update(Update::RecalculateStyle);
|
||||
}
|
||||
|
||||
@@ -181,17 +414,17 @@ void Map::resetPosition(optional<EdgeInsets> padding) {
|
||||
#pragma mark - Scale
|
||||
|
||||
void Map::scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& duration) {
|
||||
transform->scaleBy(ds, anchor, duration);
|
||||
impl->transform.scaleBy(ds, anchor, duration);
|
||||
update(Update::RecalculateStyle);
|
||||
}
|
||||
|
||||
void Map::setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& duration) {
|
||||
transform->setScale(scale, anchor, duration);
|
||||
impl->transform.setScale(scale, anchor, duration);
|
||||
update(Update::RecalculateStyle);
|
||||
}
|
||||
|
||||
double Map::getScale() const {
|
||||
return transform->getScale();
|
||||
return impl->transform.getScale();
|
||||
}
|
||||
|
||||
void Map::setZoom(double zoom, const Duration& duration) {
|
||||
@@ -199,12 +432,12 @@ void Map::setZoom(double zoom, const Duration& duration) {
|
||||
}
|
||||
|
||||
void Map::setZoom(double zoom, optional<EdgeInsets> padding, const Duration& duration) {
|
||||
transform->setZoom(zoom, padding, duration);
|
||||
impl->transform.setZoom(zoom, padding, duration);
|
||||
update(Update::RecalculateStyle);
|
||||
}
|
||||
|
||||
double Map::getZoom() const {
|
||||
return transform->getZoom();
|
||||
return impl->transform.getZoom();
|
||||
}
|
||||
|
||||
void Map::setLatLngZoom(const LatLng& latLng, double zoom, const Duration& duration) {
|
||||
@@ -212,7 +445,7 @@ void Map::setLatLngZoom(const LatLng& latLng, double zoom, const Duration& durat
|
||||
}
|
||||
|
||||
void Map::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const Duration& duration) {
|
||||
transform->setLatLngZoom(latLng, zoom, padding, duration);
|
||||
impl->transform.setLatLngZoom(latLng, zoom, padding, duration);
|
||||
update(Update::RecalculateStyle);
|
||||
}
|
||||
|
||||
@@ -285,43 +518,41 @@ void Map::resetZoom() {
|
||||
}
|
||||
|
||||
void Map::setMinZoom(const double minZoom) {
|
||||
transform->setMinZoom(minZoom);
|
||||
impl->transform.setMinZoom(minZoom);
|
||||
if (getZoom() < minZoom) {
|
||||
setZoom(minZoom);
|
||||
}
|
||||
}
|
||||
|
||||
double Map::getMinZoom() const {
|
||||
return transform->getState().getMinZoom();
|
||||
return impl->transform.getState().getMinZoom();
|
||||
}
|
||||
|
||||
void Map::setMaxZoom(const double maxZoom) {
|
||||
transform->setMaxZoom(maxZoom);
|
||||
impl->transform.setMaxZoom(maxZoom);
|
||||
if (getZoom() > maxZoom) {
|
||||
setZoom(maxZoom);
|
||||
}
|
||||
}
|
||||
|
||||
double Map::getMaxZoom() const {
|
||||
return transform->getState().getMaxZoom();
|
||||
return impl->transform.getState().getMaxZoom();
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Size
|
||||
|
||||
uint16_t Map::getWidth() const {
|
||||
return transform->getState().getWidth();
|
||||
return impl->transform.getState().getWidth();
|
||||
}
|
||||
|
||||
uint16_t Map::getHeight() const {
|
||||
return transform->getState().getHeight();
|
||||
return impl->transform.getState().getHeight();
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Rotation
|
||||
|
||||
void Map::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const Duration& duration) {
|
||||
transform->rotateBy(first, second, duration);
|
||||
impl->transform.rotateBy(first, second, duration);
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
@@ -330,25 +561,24 @@ void Map::setBearing(double degrees, const Duration& duration) {
|
||||
}
|
||||
|
||||
void Map::setBearing(double degrees, optional<ScreenCoordinate> anchor, const Duration& duration) {
|
||||
transform->setAngle(-degrees * util::DEG2RAD, anchor, duration);
|
||||
impl->transform.setAngle(-degrees * util::DEG2RAD, anchor, duration);
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
void Map::setBearing(double degrees, optional<EdgeInsets> padding, const Duration& duration) {
|
||||
transform->setAngle(-degrees * util::DEG2RAD, padding, duration);
|
||||
impl->transform.setAngle(-degrees * util::DEG2RAD, padding, duration);
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
double Map::getBearing() const {
|
||||
return -transform->getAngle() * util::RAD2DEG;
|
||||
return -impl->transform.getAngle() * util::RAD2DEG;
|
||||
}
|
||||
|
||||
void Map::resetNorth(const Duration& duration) {
|
||||
transform->setAngle(0, duration);
|
||||
impl->transform.setAngle(0, duration);
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Pitch
|
||||
|
||||
void Map::setPitch(double pitch, const Duration& duration) {
|
||||
@@ -356,35 +586,34 @@ void Map::setPitch(double pitch, const Duration& duration) {
|
||||
}
|
||||
|
||||
void Map::setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& duration) {
|
||||
transform->setPitch(pitch * util::DEG2RAD, anchor, duration);
|
||||
impl->transform.setPitch(pitch * util::DEG2RAD, anchor, duration);
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
double Map::getPitch() const {
|
||||
return transform->getPitch() * util::RAD2DEG;
|
||||
return impl->transform.getPitch() * util::RAD2DEG;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - North Orientation
|
||||
|
||||
void Map::setNorthOrientation(NorthOrientation orientation) {
|
||||
transform->setNorthOrientation(orientation);
|
||||
impl->transform.setNorthOrientation(orientation);
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
NorthOrientation Map::getNorthOrientation() const {
|
||||
return transform->getNorthOrientation();
|
||||
return impl->transform.getNorthOrientation();
|
||||
}
|
||||
|
||||
#pragma mark - Constrain mode
|
||||
|
||||
void Map::setConstrainMode(mbgl::ConstrainMode mode) {
|
||||
transform->setConstrainMode(mode);
|
||||
impl->transform.setConstrainMode(mode);
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
ConstrainMode Map::getConstrainMode() const {
|
||||
return transform->getConstrainMode();
|
||||
return impl->transform.getConstrainMode();
|
||||
}
|
||||
|
||||
#pragma mark - Projection
|
||||
@@ -402,25 +631,25 @@ LatLng Map::latLngForProjectedMeters(const ProjectedMeters& projectedMeters) con
|
||||
}
|
||||
|
||||
ScreenCoordinate Map::pixelForLatLng(const LatLng& latLng) const {
|
||||
return transform->latLngToScreenCoordinate(latLng);
|
||||
return impl->transform.latLngToScreenCoordinate(latLng);
|
||||
}
|
||||
|
||||
LatLng Map::latLngForPixel(const ScreenCoordinate& pixel) const {
|
||||
return transform->screenCoordinateToLatLng(pixel);
|
||||
return impl->transform.screenCoordinateToLatLng(pixel);
|
||||
}
|
||||
|
||||
#pragma mark - Annotations
|
||||
|
||||
void Map::addAnnotationIcon(const std::string& name, std::shared_ptr<const SpriteImage> sprite) {
|
||||
context->addAnnotationIcon(name, sprite);
|
||||
impl->data.getAnnotationManager()->addIcon(name, sprite);
|
||||
}
|
||||
|
||||
void Map::removeAnnotationIcon(const std::string& name) {
|
||||
context->removeAnnotationIcon(name);
|
||||
impl->data.getAnnotationManager()->removeIcon(name);
|
||||
}
|
||||
|
||||
double Map::getTopOffsetPixelsForAnnotationIcon(const std::string& symbol) {
|
||||
return context->getTopOffsetPixelsForAnnotationIcon(symbol);
|
||||
double Map::getTopOffsetPixelsForAnnotationIcon(const std::string& name) {
|
||||
return impl->data.getAnnotationManager()->getTopOffsetPixelsForIcon(name);
|
||||
}
|
||||
|
||||
AnnotationID Map::addPointAnnotation(const PointAnnotation& annotation) {
|
||||
@@ -428,7 +657,7 @@ AnnotationID Map::addPointAnnotation(const PointAnnotation& annotation) {
|
||||
}
|
||||
|
||||
AnnotationIDs Map::addPointAnnotations(const std::vector<PointAnnotation>& annotations) {
|
||||
auto result = data->getAnnotationManager()->addPointAnnotations(annotations, getMaxZoom());
|
||||
auto result = impl->data.getAnnotationManager()->addPointAnnotations(annotations, getMaxZoom());
|
||||
update(Update::Annotations);
|
||||
return result;
|
||||
}
|
||||
@@ -438,13 +667,13 @@ AnnotationID Map::addShapeAnnotation(const ShapeAnnotation& annotation) {
|
||||
}
|
||||
|
||||
AnnotationIDs Map::addShapeAnnotations(const std::vector<ShapeAnnotation>& annotations) {
|
||||
auto result = data->getAnnotationManager()->addShapeAnnotations(annotations, getMaxZoom());
|
||||
auto result = impl->data.getAnnotationManager()->addShapeAnnotations(annotations, getMaxZoom());
|
||||
update(Update::Annotations);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Map::updatePointAnnotation(AnnotationID annotationId, const PointAnnotation& annotation) {
|
||||
data->getAnnotationManager()->updatePointAnnotation(annotationId, annotation, getMaxZoom());
|
||||
impl->data.getAnnotationManager()->updatePointAnnotation(annotationId, annotation, getMaxZoom());
|
||||
update(Update::Annotations);
|
||||
}
|
||||
|
||||
@@ -453,12 +682,12 @@ void Map::removeAnnotation(AnnotationID annotation) {
|
||||
}
|
||||
|
||||
void Map::removeAnnotations(const AnnotationIDs& annotations) {
|
||||
data->getAnnotationManager()->removeAnnotations(annotations);
|
||||
impl->data.getAnnotationManager()->removeAnnotations(annotations);
|
||||
update(Update::Annotations);
|
||||
}
|
||||
|
||||
AnnotationIDs Map::getPointAnnotationsInBounds(const LatLngBounds& bounds) {
|
||||
return data->getAnnotationManager()->getPointAnnotationsInBounds(bounds);
|
||||
return impl->data.getAnnotationManager()->getPointAnnotationsInBounds(bounds);
|
||||
}
|
||||
|
||||
#pragma mark - Style API
|
||||
@@ -469,69 +698,108 @@ void Map::addCustomLayer(const std::string& id,
|
||||
CustomLayerDeinitializeFunction deinitialize,
|
||||
void* context_,
|
||||
const char* before) {
|
||||
view.activate();
|
||||
context->addLayer(
|
||||
impl->view.activate();
|
||||
|
||||
impl->style->addLayer(
|
||||
std::make_unique<CustomLayer>(id, initialize, render_, deinitialize, context_),
|
||||
before ? std::string(before) : optional<std::string>());
|
||||
view.deactivate();
|
||||
impl->updateFlags |= Update::Classes;
|
||||
impl->asyncUpdate.send();
|
||||
|
||||
impl->view.deactivate();
|
||||
}
|
||||
|
||||
void Map::removeCustomLayer(const std::string& id) {
|
||||
view.activate();
|
||||
context->removeLayer(id);
|
||||
view.deactivate();
|
||||
impl->view.activate();
|
||||
|
||||
impl->style->removeLayer(id);
|
||||
impl->updateFlags |= Update::Classes;
|
||||
impl->asyncUpdate.send();
|
||||
|
||||
impl->view.deactivate();
|
||||
}
|
||||
|
||||
#pragma mark - Toggles
|
||||
|
||||
void Map::setDebug(MapDebugOptions mode) {
|
||||
data->setDebug(mode);
|
||||
impl->data.setDebug(mode);
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
void Map::cycleDebugOptions() {
|
||||
data->cycleDebugOptions();
|
||||
impl->data.cycleDebugOptions();
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
MapDebugOptions Map::getDebug() const {
|
||||
return data->getDebug();
|
||||
return impl->data.getDebug();
|
||||
}
|
||||
|
||||
bool Map::isFullyLoaded() const {
|
||||
return context->isLoaded();
|
||||
return impl->style->isLoaded();
|
||||
}
|
||||
|
||||
void Map::addClass(const std::string& className, const PropertyTransition& properties) {
|
||||
context->addClass(className, properties);
|
||||
if (impl->style->addClass(className, properties)) {
|
||||
update(Update::Classes);
|
||||
}
|
||||
}
|
||||
|
||||
void Map::removeClass(const std::string& className, const PropertyTransition& properties) {
|
||||
context->removeClass(className, properties);
|
||||
if (impl->style->removeClass(className, properties)) {
|
||||
update(Update::Classes);
|
||||
}
|
||||
}
|
||||
|
||||
void Map::setClasses(const std::vector<std::string>& classNames, const PropertyTransition& properties) {
|
||||
context->setClasses(classNames, properties);
|
||||
impl->style->setClasses(classNames, properties);
|
||||
update(Update::Classes);
|
||||
}
|
||||
|
||||
bool Map::hasClass(const std::string& className) const {
|
||||
return context->hasClass(className);
|
||||
return impl->style->hasClass(className);
|
||||
}
|
||||
|
||||
std::vector<std::string> Map::getClasses() const {
|
||||
return context->getClasses();
|
||||
return impl->style->getClasses();
|
||||
}
|
||||
|
||||
void Map::setSourceTileCacheSize(size_t size) {
|
||||
context->setSourceTileCacheSize(size);
|
||||
if (size != impl->sourceCacheSize) {
|
||||
impl->sourceCacheSize = size;
|
||||
if (!impl->style) return;
|
||||
impl->style->setSourceTileCacheSize(size);
|
||||
impl->view.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void Map::onLowMemory() {
|
||||
context->onLowMemory();
|
||||
if (!impl->style) return;
|
||||
impl->style->onLowMemory();
|
||||
impl->view.invalidate();
|
||||
}
|
||||
|
||||
void Map::Impl::onResourceLoaded() {
|
||||
updateFlags |= Update::Repaint;
|
||||
asyncUpdate.send();
|
||||
}
|
||||
|
||||
void Map::Impl::onResourceError(std::exception_ptr error) {
|
||||
if (data.mode == MapMode::Still && callback) {
|
||||
callback(error, {});
|
||||
callback = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Map::dumpDebugLogs() const {
|
||||
context->dumpDebugLogs();
|
||||
Log::Info(Event::General, "--------------------------------------------------------------------------------");
|
||||
Log::Info(Event::General, "MapContext::styleURL: %s", impl->styleURL.c_str());
|
||||
if (impl->style) {
|
||||
impl->style->dumpDebugLogs();
|
||||
} else {
|
||||
Log::Info(Event::General, "no style loaded");
|
||||
}
|
||||
Log::Info(Event::General, "--------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -1,316 +0,0 @@
|
||||
#include <mbgl/map/map_context.hpp>
|
||||
#include <mbgl/map/map_data.hpp>
|
||||
#include <mbgl/map/view.hpp>
|
||||
|
||||
#include <mbgl/platform/log.hpp>
|
||||
|
||||
#include <mbgl/renderer/painter.hpp>
|
||||
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/storage/resource.hpp>
|
||||
#include <mbgl/storage/response.hpp>
|
||||
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/style/style_layer.hpp>
|
||||
#include <mbgl/style/property_transition.hpp>
|
||||
|
||||
#include <mbgl/sprite/sprite_atlas.hpp>
|
||||
#include <mbgl/sprite/sprite_store.hpp>
|
||||
|
||||
#include <mbgl/gl/gl_object_store.hpp>
|
||||
#include <mbgl/gl/texture_pool.hpp>
|
||||
|
||||
#include <mbgl/util/worker.hpp>
|
||||
#include <mbgl/util/exception.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/util/mapbox.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
MapContext::MapContext(View& view_, FileSource& fileSource_, MapMode mode_, GLContextMode contextMode_, const float pixelRatio_)
|
||||
: view(view_),
|
||||
fileSource(fileSource_),
|
||||
dataPtr(std::make_unique<MapData>(mode_, contextMode_, pixelRatio_)),
|
||||
data(*dataPtr),
|
||||
asyncUpdate([this] { update(); }),
|
||||
texturePool(std::make_unique<gl::TexturePool>()) {
|
||||
}
|
||||
|
||||
MapContext::~MapContext() {
|
||||
// Make sure we call cleanup() before deleting this object.
|
||||
assert(!style);
|
||||
}
|
||||
|
||||
void MapContext::cleanup() {
|
||||
view.activate();
|
||||
|
||||
styleRequest = nullptr;
|
||||
|
||||
// Explicit resets currently necessary because these abandon resources that need to be
|
||||
// cleaned up by glObjectStore.performCleanup();
|
||||
style.reset();
|
||||
painter.reset();
|
||||
texturePool.reset();
|
||||
dataPtr.reset();
|
||||
|
||||
glObjectStore.performCleanup();
|
||||
|
||||
view.deactivate();
|
||||
}
|
||||
|
||||
void MapContext::updateAsync(Update flags) {
|
||||
updateFlags |= flags;
|
||||
asyncUpdate.send();
|
||||
}
|
||||
|
||||
void MapContext::triggerUpdate(const TransformState& state, Update flags) {
|
||||
transformState = state;
|
||||
updateAsync(flags);
|
||||
}
|
||||
|
||||
void MapContext::setStyleURL(const std::string& url) {
|
||||
if (styleURL == url) {
|
||||
return;
|
||||
}
|
||||
|
||||
styleRequest = nullptr;
|
||||
styleURL = url;
|
||||
styleJSON.clear();
|
||||
|
||||
style = std::make_unique<Style>(data, fileSource);
|
||||
|
||||
const size_t pos = styleURL.rfind('/');
|
||||
std::string base = "";
|
||||
if (pos != std::string::npos) {
|
||||
base = styleURL.substr(0, pos + 1);
|
||||
}
|
||||
|
||||
styleRequest = fileSource.request(Resource::style(styleURL), [this, base](Response res) {
|
||||
if (res.error) {
|
||||
if (res.error->reason == Response::Error::Reason::NotFound &&
|
||||
util::mapbox::isMapboxURL(styleURL)) {
|
||||
Log::Error(Event::Setup, "style %s could not be found or is an incompatible legacy map or style", styleURL.c_str());
|
||||
} else {
|
||||
Log::Error(Event::Setup, "loading style failed: %s", res.error->message.c_str());
|
||||
}
|
||||
} else if (res.notModified || res.noContent) {
|
||||
return;
|
||||
} else {
|
||||
loadStyleJSON(*res.data, base);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void MapContext::setStyleJSON(const std::string& json, const std::string& base) {
|
||||
if (styleJSON == json) {
|
||||
return;
|
||||
}
|
||||
|
||||
styleURL.clear();
|
||||
styleJSON.clear();
|
||||
|
||||
style = std::make_unique<Style>(data, fileSource);
|
||||
|
||||
loadStyleJSON(json, base);
|
||||
}
|
||||
|
||||
void MapContext::loadStyleJSON(const std::string& json, const std::string& base) {
|
||||
style->setJSON(json, base);
|
||||
style->setObserver(this);
|
||||
styleJSON = json;
|
||||
|
||||
// force style cascade, causing all pending transitions to complete.
|
||||
style->cascade(Clock::now());
|
||||
|
||||
updateAsync(Update::Classes | Update::RecalculateStyle | Update::Annotations);
|
||||
}
|
||||
|
||||
void MapContext::update() {
|
||||
if (!style) {
|
||||
updateFlags = Update::Nothing;
|
||||
}
|
||||
|
||||
if (updateFlags == Update::Nothing || (data.mode == MapMode::Still && !callback)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This time point is used to:
|
||||
// - Calculate style property transitions;
|
||||
// - Hint style sources to notify when all its tiles are loaded;
|
||||
frameData.timePoint = Clock::now();
|
||||
|
||||
if (style->loaded && updateFlags & Update::Annotations) {
|
||||
data.getAnnotationManager()->updateStyle(*style);
|
||||
updateFlags |= Update::Classes;
|
||||
}
|
||||
|
||||
if (updateFlags & Update::Classes) {
|
||||
style->cascade(frameData.timePoint);
|
||||
}
|
||||
|
||||
if (updateFlags & Update::Classes || updateFlags & Update::RecalculateStyle) {
|
||||
style->recalculate(transformState.getZoom(), frameData.timePoint);
|
||||
}
|
||||
|
||||
style->update(transformState, frameData.timePoint, *texturePool);
|
||||
|
||||
if (data.mode == MapMode::Continuous) {
|
||||
view.invalidate();
|
||||
} else if (callback && isLoaded()) {
|
||||
view.activate();
|
||||
renderSync(transformState, frameData);
|
||||
view.deactivate();
|
||||
}
|
||||
|
||||
updateFlags = Update::Nothing;
|
||||
}
|
||||
|
||||
void MapContext::renderStill(const TransformState& state, const FrameData& frame, Map::StillImageCallback fn) {
|
||||
if (!fn) {
|
||||
Log::Error(Event::General, "StillImageCallback not set");
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.mode != MapMode::Still) {
|
||||
fn(std::make_exception_ptr(util::MisuseException("Map is not in still image render mode")), {});
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
fn(std::make_exception_ptr(util::MisuseException("Map is currently rendering an image")), {});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!style) {
|
||||
fn(std::make_exception_ptr(util::MisuseException("Map doesn't have a style")), {});
|
||||
return;
|
||||
}
|
||||
|
||||
if (style->getLastError()) {
|
||||
fn(style->getLastError(), {});
|
||||
return;
|
||||
}
|
||||
|
||||
callback = fn;
|
||||
transformState = state;
|
||||
frameData = frame;
|
||||
|
||||
updateAsync(Update::RenderStill);
|
||||
}
|
||||
|
||||
bool MapContext::renderSync(const TransformState& state, const FrameData& frame) {
|
||||
// Style was not loaded yet.
|
||||
if (!style) {
|
||||
return false;
|
||||
}
|
||||
|
||||
transformState = state;
|
||||
frameData = frame;
|
||||
|
||||
if (!painter) painter = std::make_unique<Painter>(data, transformState, glObjectStore);
|
||||
painter->render(*style, frame, data.getAnnotationManager()->getSpriteAtlas());
|
||||
|
||||
if (data.mode == MapMode::Still) {
|
||||
callback(nullptr, view.readStillImage());
|
||||
callback = nullptr;
|
||||
}
|
||||
|
||||
// Cleanup OpenGL objects that we abandoned since the last render call.
|
||||
glObjectStore.performCleanup();
|
||||
|
||||
if (style->hasTransitions()) {
|
||||
updateAsync(Update::RecalculateStyle);
|
||||
} else if (painter->needsAnimation()) {
|
||||
updateAsync(Update::Repaint);
|
||||
}
|
||||
|
||||
return isLoaded();
|
||||
}
|
||||
|
||||
bool MapContext::isLoaded() const {
|
||||
return style->isLoaded();
|
||||
}
|
||||
|
||||
void MapContext::addAnnotationIcon(const std::string& name, std::shared_ptr<const SpriteImage> sprite) {
|
||||
data.getAnnotationManager()->addIcon(name, sprite);
|
||||
}
|
||||
|
||||
void MapContext::removeAnnotationIcon(const std::string& name) {
|
||||
data.getAnnotationManager()->removeIcon(name);
|
||||
}
|
||||
|
||||
double MapContext::getTopOffsetPixelsForAnnotationIcon(const std::string& name) {
|
||||
return data.getAnnotationManager()->getTopOffsetPixelsForIcon(name);
|
||||
}
|
||||
|
||||
void MapContext::addLayer(std::unique_ptr<StyleLayer> layer, optional<std::string> after) {
|
||||
style->addLayer(std::move(layer), after);
|
||||
updateAsync(Update::Classes);
|
||||
}
|
||||
|
||||
void MapContext::removeLayer(const std::string& id) {
|
||||
style->removeLayer(id);
|
||||
updateAsync(Update::Classes);
|
||||
}
|
||||
|
||||
std::vector<std::string> MapContext::getClasses() const {
|
||||
return style->getClasses();
|
||||
}
|
||||
|
||||
bool MapContext::hasClass(const std::string& className) const {
|
||||
return style->hasClass(className);
|
||||
}
|
||||
|
||||
void MapContext::addClass(const std::string& className, const PropertyTransition& properties) {
|
||||
if (style->addClass(className, properties)) updateAsync(Update::Classes);
|
||||
}
|
||||
|
||||
void MapContext::removeClass(const std::string& className, const PropertyTransition& properties) {
|
||||
if (style->removeClass(className, properties)) updateAsync(Update::Classes);
|
||||
}
|
||||
|
||||
void MapContext::setClasses(const std::vector<std::string>& classNames, const PropertyTransition& properties) {
|
||||
style->setClasses(classNames, properties);
|
||||
updateAsync(Update::Classes);
|
||||
}
|
||||
|
||||
void MapContext::setSourceTileCacheSize(size_t size) {
|
||||
if (size != sourceCacheSize) {
|
||||
sourceCacheSize = size;
|
||||
if (!style) return;
|
||||
style->setSourceTileCacheSize(size);
|
||||
view.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void MapContext::onLowMemory() {
|
||||
if (!style) return;
|
||||
style->onLowMemory();
|
||||
view.invalidate();
|
||||
}
|
||||
|
||||
void MapContext::onResourceLoaded() {
|
||||
updateAsync(Update::Repaint);
|
||||
}
|
||||
|
||||
void MapContext::onResourceError(std::exception_ptr error) {
|
||||
if (data.mode == MapMode::Still && callback) {
|
||||
callback(error, {});
|
||||
callback = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MapContext::dumpDebugLogs() const {
|
||||
Log::Info(Event::General, "--------------------------------------------------------------------------------");
|
||||
Log::Info(Event::General, "MapContext::styleURL: %s", styleURL.c_str());
|
||||
if (style) {
|
||||
style->dumpDebugLogs();
|
||||
} else {
|
||||
Log::Info(Event::General, "no style loaded");
|
||||
}
|
||||
Log::Info(Event::General, "--------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
} // namespace mbgl
|
||||
@@ -1,116 +0,0 @@
|
||||
#ifndef MBGL_MAP_MAP_CONTEXT
|
||||
#define MBGL_MAP_MAP_CONTEXT
|
||||
|
||||
#include <mbgl/map/tile_id.hpp>
|
||||
#include <mbgl/map/update.hpp>
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/map/map_data.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/util/async_task.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
#include <mbgl/util/optional.hpp>
|
||||
#include <mbgl/gl/gl_object_store.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class View;
|
||||
class MapData;
|
||||
class Painter;
|
||||
class SpriteImage;
|
||||
class AsyncRequest;
|
||||
class PropertyTransition;
|
||||
|
||||
namespace gl { class TexturePool; }
|
||||
|
||||
struct FrameData {
|
||||
std::array<uint16_t, 2> framebufferSize;
|
||||
TimePoint timePoint;
|
||||
};
|
||||
|
||||
class MapContext : public Style::Observer {
|
||||
public:
|
||||
MapContext(View&, FileSource&, MapMode, GLContextMode, const float pixelRatio);
|
||||
~MapContext();
|
||||
|
||||
MapData& getData() { return data; }
|
||||
|
||||
void triggerUpdate(const TransformState&, Update = Update::Nothing);
|
||||
void renderStill(const TransformState&, const FrameData&, Map::StillImageCallback callback);
|
||||
|
||||
// Triggers a synchronous render. Returns true if style has been fully loaded.
|
||||
bool renderSync(const TransformState&, const FrameData&);
|
||||
|
||||
void setStyleURL(const std::string&);
|
||||
void setStyleJSON(const std::string& json, const std::string& base);
|
||||
std::string getStyleURL() const { return styleURL; }
|
||||
std::string getStyleJSON() const { return styleJSON; }
|
||||
|
||||
bool isLoaded() const;
|
||||
|
||||
// Annotations
|
||||
void addAnnotationIcon(const std::string&, std::shared_ptr<const SpriteImage>);
|
||||
void removeAnnotationIcon(const std::string&);
|
||||
double getTopOffsetPixelsForAnnotationIcon(const std::string&);
|
||||
void updateAnnotations();
|
||||
|
||||
// Style API
|
||||
void addLayer(std::unique_ptr<StyleLayer>,
|
||||
const optional<std::string> before);
|
||||
void removeLayer(const std::string& id);
|
||||
|
||||
void addClass(const std::string&, const PropertyTransition&);
|
||||
void removeClass(const std::string&, const PropertyTransition&);
|
||||
bool hasClass(const std::string&) const;
|
||||
void setClasses(const std::vector<std::string>&, const PropertyTransition&);
|
||||
std::vector<std::string> getClasses() const;
|
||||
|
||||
void setSourceTileCacheSize(size_t size);
|
||||
void onLowMemory();
|
||||
|
||||
void cleanup();
|
||||
void dumpDebugLogs() const;
|
||||
|
||||
private:
|
||||
void onResourceLoaded() override;
|
||||
void onResourceError(std::exception_ptr) override;
|
||||
|
||||
// Update the state indicated by the accumulated Update flags, then render.
|
||||
void update();
|
||||
|
||||
// Helper function for triggering asynchronous updates.
|
||||
void updateAsync(Update);
|
||||
|
||||
// Loads the actual JSON object an creates a new Style object.
|
||||
void loadStyleJSON(const std::string& json, const std::string& base);
|
||||
|
||||
View& view;
|
||||
FileSource& fileSource;
|
||||
std::unique_ptr<MapData> dataPtr;
|
||||
MapData& data;
|
||||
|
||||
gl::GLObjectStore glObjectStore;
|
||||
|
||||
Update updateFlags = Update::Nothing;
|
||||
util::AsyncTask asyncUpdate;
|
||||
|
||||
std::unique_ptr<gl::TexturePool> texturePool;
|
||||
std::unique_ptr<Painter> painter;
|
||||
std::unique_ptr<Style> style;
|
||||
|
||||
std::string styleURL;
|
||||
std::string styleJSON;
|
||||
|
||||
std::unique_ptr<AsyncRequest> styleRequest;
|
||||
|
||||
Map::StillImageCallback callback;
|
||||
size_t sourceCacheSize;
|
||||
TransformState transformState;
|
||||
FrameData frameData;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <mbgl/source/source.hpp>
|
||||
#include <mbgl/tile/tile.hpp>
|
||||
#include <mbgl/map/map_context.hpp>
|
||||
#include <mbgl/map/map_data.hpp>
|
||||
|
||||
#include <mbgl/platform/log.hpp>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define MBGL_RENDERER_PAINTER
|
||||
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
#include <mbgl/map/map_context.hpp>
|
||||
|
||||
#include <mbgl/renderer/frame_history.hpp>
|
||||
#include <mbgl/renderer/bucket.hpp>
|
||||
@@ -13,6 +12,7 @@
|
||||
#include <mbgl/gl/gl_config.hpp>
|
||||
|
||||
#include <mbgl/style/types.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
|
||||
#include <mbgl/gl/gl.hpp>
|
||||
|
||||
@@ -23,9 +23,11 @@
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class MapData;
|
||||
class Style;
|
||||
class StyleLayer;
|
||||
class Tile;
|
||||
@@ -34,6 +36,7 @@ class GlyphAtlas;
|
||||
class LineAtlas;
|
||||
class Source;
|
||||
struct FrameData;
|
||||
class TileData;
|
||||
|
||||
class DebugBucket;
|
||||
class FillBucket;
|
||||
@@ -70,6 +73,11 @@ namespace util {
|
||||
class GLObjectStore;
|
||||
}
|
||||
|
||||
struct FrameData {
|
||||
std::array<uint16_t, 2> framebufferSize;
|
||||
TimePoint timePoint;
|
||||
};
|
||||
|
||||
class Painter : private util::noncopyable {
|
||||
public:
|
||||
Painter(MapData&, TransformState&, gl::GLObjectStore&);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <mbgl/layer/background_layer.hpp>
|
||||
#include <mbgl/shader/pattern_shader.hpp>
|
||||
#include <mbgl/shader/plain_shader.hpp>
|
||||
#include <mbgl/sprite/sprite_atlas.hpp>
|
||||
#include <mbgl/util/mat4.hpp>
|
||||
#include <mbgl/util/tile_cover.hpp>
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <mbgl/test/util.hpp>
|
||||
#include <mbgl/test/stub_file_source.hpp>
|
||||
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
@@ -44,3 +45,15 @@ TEST(Map, Offline) {
|
||||
|
||||
NetworkStatus::Set(NetworkStatus::Status::Online);
|
||||
}
|
||||
|
||||
TEST(Map, DoubleStyleLoad) {
|
||||
util::RunLoop runLoop;
|
||||
|
||||
std::shared_ptr<HeadlessDisplay> display = std::make_shared<HeadlessDisplay>();
|
||||
HeadlessView view(display, 1, 512, 512);
|
||||
StubFileSource fileSource;
|
||||
|
||||
Map map(view, fileSource);
|
||||
map.setStyleJSON("", "");
|
||||
map.setStyleJSON("", "");
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
#include <mbgl/test/util.hpp>
|
||||
#include <mbgl/test/stub_file_source.hpp>
|
||||
|
||||
#include <mbgl/map/map_data.hpp>
|
||||
#include <mbgl/map/map_context.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/headless_display.hpp>
|
||||
#include <mbgl/util/thread.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
TEST(MapContext, DoubleStyleLoad) {
|
||||
util::RunLoop loop;
|
||||
|
||||
std::shared_ptr<HeadlessDisplay> display = std::make_shared<HeadlessDisplay>();
|
||||
HeadlessView view(display, 1, 512, 512);
|
||||
StubFileSource fileSource;
|
||||
|
||||
util::Thread<MapContext> context({"Map"},
|
||||
view, fileSource, MapMode::Continuous, GLContextMode::Unique, view.getPixelRatio());
|
||||
|
||||
context.invokeSync(&MapContext::setStyleJSON, "", "");
|
||||
context.invokeSync(&MapContext::setStyleJSON, "", "");
|
||||
context.invokeSync(&MapContext::cleanup);
|
||||
}
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
'geometry/binpack.cpp',
|
||||
|
||||
'map/map_context.cpp',
|
||||
'map/map.cpp',
|
||||
'map/tile.cpp',
|
||||
'map/transform.cpp',
|
||||
|
||||
|
||||
Reference in New Issue
Block a user