diff options
Diffstat (limited to 'src/mbgl/map')
-rw-r--r-- | src/mbgl/map/backend.cpp | 19 | ||||
-rw-r--r-- | src/mbgl/map/map.cpp | 455 | ||||
-rw-r--r-- | src/mbgl/map/transform.cpp | 5 | ||||
-rw-r--r-- | src/mbgl/map/transform_state.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/map/update.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/map/zoom_history.hpp | 7 |
6 files changed, 119 insertions, 371 deletions
diff --git a/src/mbgl/map/backend.cpp b/src/mbgl/map/backend.cpp index 0b4fd01050..83c2fed00b 100644 --- a/src/mbgl/map/backend.cpp +++ b/src/mbgl/map/backend.cpp @@ -32,11 +32,17 @@ void Backend::assumeFramebufferBinding(const gl::FramebufferID fbo) { assert(gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue()); } } -void Backend::assumeViewportSize(const Size& size) { - getContext().viewport.setCurrentValue({ 0, 0, size }); + +void Backend::assumeViewport(int32_t x, int32_t y, const Size& size) { + getContext().viewport.setCurrentValue({ x, y, size }); assert(gl::value::Viewport::Get() == getContext().viewport.getCurrentValue()); } +void Backend::assumeScissorTest(bool enabled) { + getContext().scissorTest.setCurrentValue(enabled); + assert(gl::value::ScissorTest::Get() == getContext().scissorTest.getCurrentValue()); +} + bool Backend::implicitFramebufferBound() { return getContext().bindFramebuffer.getCurrentValue() == ImplicitFramebufferBinding; } @@ -48,11 +54,16 @@ void Backend::setFramebufferBinding(const gl::FramebufferID fbo) { } } -void Backend::setViewportSize(const Size& size) { - getContext().viewport = { 0, 0, size }; +void Backend::setViewport(int32_t x, int32_t y, const Size& size) { + getContext().viewport = { x, y, size }; assert(gl::value::Viewport::Get() == getContext().viewport.getCurrentValue()); } +void Backend::setScissorTest(bool enabled) { + getContext().scissorTest = enabled; + assert(gl::value::ScissorTest::Get() == getContext().scissorTest.getCurrentValue()); +} + Backend::~Backend() = default; } // namespace mbgl diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 35457f3a5b..034e43f260 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -6,18 +6,13 @@ #include <mbgl/map/transform.hpp> #include <mbgl/map/transform_state.hpp> #include <mbgl/annotation/annotation_manager.hpp> -#include <mbgl/style/style.hpp> -#include <mbgl/style/source.hpp> -#include <mbgl/style/layer.hpp> -#include <mbgl/style/light.hpp> +#include <mbgl/style/style_impl.hpp> #include <mbgl/style/observer.hpp> -#include <mbgl/style/transition_options.hpp> #include <mbgl/renderer/update_parameters.hpp> #include <mbgl/renderer/painter.hpp> #include <mbgl/renderer/render_source.hpp> -#include <mbgl/storage/file_source.hpp> -#include <mbgl/storage/resource.hpp> -#include <mbgl/storage/response.hpp> +#include <mbgl/renderer/render_style.hpp> +#include <mbgl/renderer/render_style_observer.hpp> #include <mbgl/util/exception.hpp> #include <mbgl/util/math.hpp> #include <mbgl/util/exception.hpp> @@ -27,6 +22,7 @@ #include <mbgl/actor/scheduler.hpp> #include <mbgl/util/logging.hpp> #include <mbgl/math/log2.hpp> +#include <utility> namespace mbgl { @@ -47,7 +43,8 @@ struct StillImageRequest { Map::StillImageCallback callback; }; -class Map::Impl : public style::Observer { +class Map::Impl : public style::Observer, + public RenderStyleObserver { public: Impl(Map&, Backend&, @@ -62,6 +59,8 @@ public: void onSourceChanged(style::Source&) override; void onUpdate(Update) override; + void onInvalidate() override; + void onStyleLoading() override; void onStyleLoaded() override; void onStyleError(std::exception_ptr) override; void onResourceError(std::exception_ptr) override; @@ -69,8 +68,6 @@ public: void render(View&); void renderStill(); - void loadStyleJSON(const std::string&); - Map& map; MapObserver& observer; Backend& backend; @@ -89,18 +86,12 @@ public: Update updateFlags = Update::Nothing; - std::unique_ptr<AnnotationManager> annotationManager; + AnnotationManager annotationManager; std::unique_ptr<Painter> painter; std::unique_ptr<Style> style; + std::unique_ptr<RenderStyle> renderStyle; - std::string styleURL; - std::string styleJSON; - bool styleMutated = false; bool cameraMutated = false; - - std::unique_ptr<AsyncRequest> styleRequest; - - size_t sourceCacheSize; bool loading = false; util::AsyncTask asyncInvalidate; @@ -151,8 +142,7 @@ Map::Impl::Impl(Map& map_, mode(mode_), contextMode(contextMode_), pixelRatio(pixelRatio_), - programCacheDir(programCacheDir_), - annotationManager(std::make_unique<AnnotationManager>(pixelRatio)), + programCacheDir(std::move(programCacheDir_)), asyncInvalidate([this] { if (mode == MapMode::Continuous) { backend.invalidate(); @@ -160,17 +150,16 @@ Map::Impl::Impl(Map& map_, renderStill(); } }) { + style = std::make_unique<Style>(scheduler, fileSource, pixelRatio); + style->impl->setObserver(this); } Map::~Map() { BackendScope guard(impl->backend); - impl->styleRequest = nullptr; - // Explicit resets currently necessary because these abandon resources that need to be // cleaned up by context.reset(); - impl->style.reset(); - impl->annotationManager.reset(); + impl->renderStyle.reset(); impl->painter.reset(); } @@ -190,13 +179,8 @@ void Map::renderStill(View& view, StillImageCallback callback) { 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()); + if (impl->style->impl->getLastError()) { + callback(impl->style->impl->getLastError()); return; } @@ -223,42 +207,48 @@ void Map::render(View& view) { } void Map::Impl::render(View& view) { - if (!style) { - return; - } - TimePoint timePoint = mode == MapMode::Continuous ? Clock::now() : Clock::time_point::max(); transform.updateTransitions(timePoint); - if (style->loaded && updateFlags & Update::AnnotationStyle) { - annotationManager->updateStyle(*style); + if (style->impl->loaded && updateFlags & Update::AnnotationStyle) { + annotationManager.updateStyle(*style->impl); } if (updateFlags & Update::AnnotationData) { - annotationManager->updateData(); + annotationManager.updateData(); } - style->update({ + updateFlags = Update::Nothing; + + gl::Context& context = backend.getContext(); + if (!painter) { + renderStyle = std::make_unique<RenderStyle>(scheduler, fileSource); + renderStyle->setObserver(this); + painter = std::make_unique<Painter>(context, transform.getState(), pixelRatio, programCacheDir); + } + + renderStyle->update({ mode, - updateFlags, pixelRatio, debugOptions, timePoint, transform.getState(), + style->impl->getGlyphURL(), + style->impl->spriteLoaded, + style->impl->getTransitionOptions(), + style->impl->getLight()->impl, + style->impl->getImageImpls(), + style->impl->getSourceImpls(), + style->impl->getLayerImpls(), scheduler, fileSource, - *annotationManager + annotationManager }); - updateFlags = Update::Nothing; - - gl::Context& context = backend.getContext(); - if (!painter) { - painter = std::make_unique<Painter>(context, transform.getState(), pixelRatio, programCacheDir); - } + bool loaded = style->impl->isLoaded() && renderStyle->isLoaded(); if (mode == MapMode::Continuous) { if (renderState == RenderState::Never) { @@ -275,16 +265,17 @@ void Map::Impl::render(View& view) { backend.updateAssumedState(); - painter->render(*style, + painter->render(*renderStyle, frameData, - view, - annotationManager->getSpriteAtlas()); + view); painter->cleanup(); - observer.onDidFinishRenderingFrame(style->isLoaded() ? MapObserver::RenderMode::Full : MapObserver::RenderMode::Partial); + observer.onDidFinishRenderingFrame(loaded + ? MapObserver::RenderMode::Full + : MapObserver::RenderMode::Partial); - if (!style->isLoaded()) { + if (!loaded) { renderState = RenderState::Partial; } else if (renderState != RenderState::Fully) { renderState = RenderState::Fully; @@ -297,10 +288,10 @@ void Map::Impl::render(View& view) { // Schedule an update if we need to paint another frame due to transitions or // animations that are still in progress - if (style->hasTransitions() || painter->needsAnimation() || transform.inTransition()) { + if (renderStyle->hasTransitions() || painter->needsAnimation() || transform.inTransition()) { onUpdate(Update::Repaint); } - } else if (stillImageRequest && style->isLoaded()) { + } else if (stillImageRequest && loaded) { FrameData frameData { timePoint, pixelRatio, mode, @@ -309,10 +300,9 @@ void Map::Impl::render(View& view) { backend.updateAssumedState(); - painter->render(*style, + painter->render(*renderStyle, frameData, - view, - annotationManager->getSpriteAtlas()); + view); auto request = std::move(stillImageRequest); request->callback(nullptr); @@ -323,93 +313,17 @@ void Map::Impl::render(View& view) { #pragma mark - Style -void Map::setStyleURL(const std::string& url) { - if (impl->styleURL == url) { - return; - } - - impl->loading = true; - - impl->observer.onWillStartLoadingMap(); - - impl->styleRequest = nullptr; - impl->styleURL = url; - impl->styleJSON.clear(); - impl->styleMutated = false; - - impl->style = std::make_unique<Style>(impl->scheduler, impl->fileSource, impl->pixelRatio); - - impl->styleRequest = impl->fileSource.request(Resource::style(impl->styleURL), [this](Response res) { - // Once we get a fresh style, or the style is mutated, stop revalidating. - if (res.isFresh() || impl->styleMutated) { - impl->styleRequest.reset(); - } - - // Don't allow a loaded, mutated style to be overwritten with a new version. - if (impl->styleMutated && impl->style->loaded) { - return; - } - - if (res.error) { - if (res.error->reason == Response::Error::Reason::NotFound && - util::mapbox::isMapboxURL(impl->styleURL)) { - const std::string message = "style " + impl->styleURL + " could not be found or is an incompatible legacy map or style"; - Log::Error(Event::Setup, message.c_str()); - impl->onStyleError(std::make_exception_ptr(util::NotFoundException(message))); - } else { - const std::string message = "loading style failed: " + res.error->message; - Log::Error(Event::Setup, message.c_str()); - impl->onStyleError(std::make_exception_ptr(util::StyleLoadException(message))); - } - impl->onResourceError(std::make_exception_ptr(std::runtime_error(res.error->message))); - } else if (res.notModified || res.noContent) { - return; - } else { - impl->loadStyleJSON(*res.data); - } - }); +style::Style& Map::getStyle() { + return *impl->style; } -void Map::setStyleJSON(const std::string& json) { - if (impl->styleJSON == json) { - return; - } - - impl->loading = true; - - impl->observer.onWillStartLoadingMap(); - - impl->styleURL.clear(); - impl->styleJSON.clear(); - impl->styleMutated = false; - - impl->style = std::make_unique<Style>(impl->scheduler, impl->fileSource, impl->pixelRatio); - - impl->loadStyleJSON(json); -} - -void Map::Impl::loadStyleJSON(const std::string& json) { - style->setObserver(this); - style->setJSON(json); - styleJSON = json; - - if (!cameraMutated) { - // Zoom first because it may constrain subsequent operations. - map.setZoom(map.getDefaultZoom()); - map.setLatLng(map.getDefaultLatLng()); - map.setBearing(map.getDefaultBearing()); - map.setPitch(map.getDefaultPitch()); - } - - onUpdate(Update::Classes | Update::AnnotationStyle); -} - -std::string Map::getStyleURL() const { - return impl->styleURL; +const style::Style& Map::getStyle() const { + return *impl->style; } -std::string Map::getStyleJSON() const { - return impl->styleJSON; +void Map::setStyle(std::unique_ptr<Style> style) { + impl->onStyleLoading(); + impl->style = std::move(style); } #pragma mark - Transitions @@ -787,39 +701,41 @@ LatLng Map::latLngForPixel(const ScreenCoordinate& pixel) const { #pragma mark - Annotations -void Map::addAnnotationImage(const std::string& id, std::unique_ptr<style::Image> image) { - impl->annotationManager->addImage(id, std::move(image)); +void Map::addAnnotationImage(std::unique_ptr<style::Image> image) { + impl->annotationManager.addImage(std::move(image)); + impl->onUpdate(Update::AnnotationStyle); } void Map::removeAnnotationImage(const std::string& id) { - impl->annotationManager->removeImage(id); + impl->annotationManager.removeImage(id); + impl->onUpdate(Update::AnnotationStyle); } double Map::getTopOffsetPixelsForAnnotationImage(const std::string& id) { - return impl->annotationManager->getTopOffsetPixelsForImage(id); + return impl->annotationManager.getTopOffsetPixelsForImage(id); } AnnotationID Map::addAnnotation(const Annotation& annotation) { - auto result = impl->annotationManager->addAnnotation(annotation, getMaxZoom()); + auto result = impl->annotationManager.addAnnotation(annotation, getMaxZoom()); impl->onUpdate(Update::AnnotationStyle | Update::AnnotationData); return result; } void Map::updateAnnotation(AnnotationID id, const Annotation& annotation) { - impl->onUpdate(impl->annotationManager->updateAnnotation(id, annotation, getMaxZoom())); + impl->onUpdate(impl->annotationManager.updateAnnotation(id, annotation, getMaxZoom())); } void Map::removeAnnotation(AnnotationID annotation) { - impl->annotationManager->removeAnnotation(annotation); + impl->annotationManager.removeAnnotation(annotation); impl->onUpdate(Update::AnnotationStyle | Update::AnnotationData); } #pragma mark - Feature query api std::vector<Feature> Map::queryRenderedFeatures(const ScreenCoordinate& point, const RenderedQueryOptions& options) { - if (!impl->style) return {}; + if (!impl->renderStyle) return {}; - return impl->style->queryRenderedFeatures( + return impl->renderStyle->queryRenderedFeatures( { point }, impl->transform.getState(), options @@ -827,9 +743,9 @@ std::vector<Feature> Map::queryRenderedFeatures(const ScreenCoordinate& point, c } std::vector<Feature> Map::queryRenderedFeatures(const ScreenBox& box, const RenderedQueryOptions& options) { - if (!impl->style) return {}; + if (!impl->renderStyle) return {}; - return impl->style->queryRenderedFeatures( + return impl->renderStyle->queryRenderedFeatures( { box.min, { box.max.x, box.min.y }, @@ -843,9 +759,9 @@ std::vector<Feature> Map::queryRenderedFeatures(const ScreenBox& box, const Rend } std::vector<Feature> Map::querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options) { - if (!impl->style) return {}; + if (!impl->renderStyle) return {}; - const RenderSource* source = impl->style->getRenderSource(sourceID); + const RenderSource* source = impl->renderStyle->getRenderSource(sourceID); if (!source) return {}; return source->querySourceFeatures(options); @@ -868,153 +784,6 @@ AnnotationIDs Map::queryPointAnnotations(const ScreenBox& box) { return ids; } -#pragma mark - Style API - -std::vector<style::Source*> Map::getSources() { - return impl->style ? impl->style->getSources() : std::vector<style::Source*>(); -} - -style::Source* Map::getSource(const std::string& sourceID) { - if (impl->style) { - impl->styleMutated = true; - return impl->style->getSource(sourceID); - } - return nullptr; -} - -void Map::addSource(std::unique_ptr<style::Source> source) { - if (impl->style) { - impl->styleMutated = true; - impl->style->addSource(std::move(source)); - } -} - -std::unique_ptr<Source> Map::removeSource(const std::string& sourceID) { - if (impl->style) { - impl->styleMutated = true; - return impl->style->removeSource(sourceID); - } - return nullptr; -} - -std::vector<style::Layer*> Map::getLayers() { - return impl->style ? impl->style->getLayers() : std::vector<style::Layer*>(); -} - -Layer* Map::getLayer(const std::string& layerID) { - if (impl->style) { - impl->styleMutated = true; - return impl->style->getLayer(layerID); - } - return nullptr; -} - -void Map::addLayer(std::unique_ptr<Layer> layer, const optional<std::string>& before) { - if (!impl->style) { - return; - } - - impl->styleMutated = true; - BackendScope guard(impl->backend); - - impl->style->addLayer(std::move(layer), before); - impl->onUpdate(Update::Classes); -} - -std::unique_ptr<Layer> Map::removeLayer(const std::string& id) { - if (!impl->style) { - return nullptr; - } - - impl->styleMutated = true; - BackendScope guard(impl->backend); - - auto removedLayer = impl->style->removeLayer(id); - impl->onUpdate(Update::Repaint); - - return removedLayer; -} - -void Map::addImage(const std::string& id, std::unique_ptr<style::Image> image) { - if (!impl->style) { - return; - } - - impl->styleMutated = true; - impl->style->spriteAtlas->addImage(id, std::move(image)); - impl->onUpdate(Update::Repaint); -} - -void Map::removeImage(const std::string& id) { - if (!impl->style) { - return; - } - - impl->styleMutated = true; - impl->style->spriteAtlas->removeImage(id); - impl->onUpdate(Update::Repaint); -} - -const style::Image* Map::getImage(const std::string& id) { - if (impl->style) { - return impl->style->spriteAtlas->getImage(id); - } - return nullptr; -} - -void Map::setLight(std::unique_ptr<style::Light> light) { - if (!impl->style) { - return; - } - - impl->style->setLight(std::move(light)); -} - -style::Light* Map::getLight() { - if (!impl->style) { - return nullptr; - } - - return impl->style->getLight(); -} - -#pragma mark - Defaults - -std::string Map::getStyleName() const { - if (impl->style) { - return impl->style->getName(); - } - return {}; -} - -LatLng Map::getDefaultLatLng() const { - if (impl->style) { - return impl->style->getDefaultLatLng(); - } - return {}; -} - -double Map::getDefaultZoom() const { - if (impl->style) { - return impl->style->getDefaultZoom(); - } - return {}; -} - -double Map::getDefaultBearing() const { - if (impl->style) { - return impl->style->getDefaultBearing(); - } - return {}; -} - -double Map::getDefaultPitch() const { - if (impl->style) { - return impl->style->getDefaultPitch(); - } - return {}; -} - #pragma mark - Toggles void Map::setDebug(MapDebugOptions debugOptions) { @@ -1051,59 +820,7 @@ MapDebugOptions Map::getDebug() const { } bool Map::isFullyLoaded() const { - return impl->style ? impl->style->isLoaded() : false; -} - -void Map::addClass(const std::string& className) { - if (impl->style && impl->style->addClass(className)) { - impl->onUpdate(Update::Classes); - } -} - -void Map::removeClass(const std::string& className) { - if (impl->style && impl->style->removeClass(className)) { - impl->onUpdate(Update::Classes); - } -} - -void Map::setClasses(const std::vector<std::string>& classNames) { - if (impl->style) { - impl->style->setClasses(classNames); - impl->onUpdate(Update::Classes); - } -} - -style::TransitionOptions Map::getTransitionOptions() const { - if (impl->style) { - return impl->style->getTransitionOptions(); - } - return {}; -} - -void Map::setTransitionOptions(const style::TransitionOptions& options) { - if (impl->style) { - impl->style->setTransitionOptions(options); - } -} - -bool Map::hasClass(const std::string& className) const { - return impl->style ? impl->style->hasClass(className) : false; -} - -std::vector<std::string> Map::getClasses() const { - if (impl->style) { - return impl->style->getClasses(); - } - return {}; -} - -void Map::setSourceTileCacheSize(size_t size) { - if (size != impl->sourceCacheSize) { - impl->sourceCacheSize = size; - if (!impl->style) return; - impl->style->setSourceTileCacheSize(size); - impl->backend.invalidate(); - } + return impl->style->impl->isLoaded() && impl->renderStyle && impl->renderStyle->isLoaded(); } void Map::onLowMemory() { @@ -1111,8 +828,8 @@ void Map::onLowMemory() { BackendScope guard(impl->backend); impl->painter->cleanup(); } - if (impl->style) { - impl->style->onLowMemory(); + if (impl->renderStyle) { + impl->renderStyle->onLowMemory(); impl->backend.invalidate(); } } @@ -1126,7 +843,25 @@ void Map::Impl::onUpdate(Update flags) { asyncInvalidate.send(); } +void Map::Impl::onInvalidate() { + onUpdate(Update::Repaint); +} + +void Map::Impl::onStyleLoading() { + loading = true; + observer.onWillStartLoadingMap(); +} + void Map::Impl::onStyleLoaded() { + if (!cameraMutated) { + // Zoom first because it may constrain subsequent operations. + map.setZoom(style->getDefaultZoom()); + map.setLatLng(style->getDefaultLatLng()); + map.setBearing(style->getDefaultBearing()); + map.setPitch(style->getDefaultPitch()); + } + + onUpdate(Update::AnnotationStyle); observer.onDidFinishLoadingStyle(); } @@ -1143,11 +878,9 @@ void Map::Impl::onResourceError(std::exception_ptr error) { void Map::dumpDebugLogs() const { 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"); + impl->style->impl->dumpDebugLogs(); + if (impl->renderStyle) { + impl->renderStyle->dumpDebugLogs(); } Log::Info(Event::General, "--------------------------------------------------------------------------------"); } diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 8d05bc0e91..50f979437d 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -293,6 +293,11 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima Point<double> framePoint = util::interpolate(startPoint, endPoint, us); double frameZoom = startZoom + state.scaleZoom(1 / w(s)); + // Zoom can be NaN if size is empty. + if (std::isnan(frameZoom)) { + frameZoom = zoom; + } + // Convert to geographic coordinates and set the new viewpoint. LatLng frameLatLng = Projection::unproject(framePoint, startScale); state.setLatLngZoom(frameLatLng, frameZoom); diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index bbf7e22b31..f052e30a6b 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -358,7 +358,7 @@ void TransformState::setLatLngZoom(const LatLng& latLng, double zoom) { constrained = bounds->constrain(latLng); } - double newScale = zoomScale(zoom); + double newScale = util::clamp(zoomScale(zoom), min_scale, max_scale); const double newWorldSize = newScale * util::tileSize; Bc = newWorldSize / util::DEGREES_MAX; Cc = newWorldSize / util::M2PI; diff --git a/src/mbgl/map/update.hpp b/src/mbgl/map/update.hpp index 5e87515eac..82d98284f5 100644 --- a/src/mbgl/map/update.hpp +++ b/src/mbgl/map/update.hpp @@ -7,8 +7,6 @@ namespace mbgl { enum class Update { Nothing = 0, Repaint = 1 << 0, - Classes = 1 << 2, - RecalculateStyle = 1 << 3, AnnotationStyle = 1 << 6, AnnotationData = 1 << 7 }; diff --git a/src/mbgl/map/zoom_history.hpp b/src/mbgl/map/zoom_history.hpp index 308846b1e3..697e28573c 100644 --- a/src/mbgl/map/zoom_history.hpp +++ b/src/mbgl/map/zoom_history.hpp @@ -13,19 +13,20 @@ struct ZoomHistory { bool first = true; bool update(float z, const TimePoint& now) { + constexpr TimePoint zero = TimePoint(Duration::zero()); if (first) { first = false; lastIntegerZoom = std::floor(z); - lastIntegerZoomTime = TimePoint(Duration::zero()); + lastIntegerZoomTime = zero; lastZoom = z; return true; } else { if (std::floor(lastZoom) < std::floor(z)) { lastIntegerZoom = std::floor(z); - lastIntegerZoomTime = now; + lastIntegerZoomTime = now == Clock::time_point::max() ? zero : now; } else if (std::floor(lastZoom) > std::floor(z)) { lastIntegerZoom = std::floor(z + 1); - lastIntegerZoomTime = now; + lastIntegerZoomTime = now == Clock::time_point::max() ? zero : now; } if (z != lastZoom) { |