diff options
Diffstat (limited to 'src/mbgl/style')
82 files changed, 3405 insertions, 2942 deletions
diff --git a/src/mbgl/style/class_dictionary.cpp b/src/mbgl/style/class_dictionary.cpp deleted file mode 100644 index ec06ee7d9d..0000000000 --- a/src/mbgl/style/class_dictionary.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include <mbgl/style/class_dictionary.hpp> - -#include <pthread.h> - -namespace mbgl { -namespace style { - -ClassDictionary::ClassDictionary() {} - -ClassDictionary &ClassDictionary::Get() { - static pthread_once_t store_once = PTHREAD_ONCE_INIT; - static pthread_key_t store_key; - - // Create the key. - pthread_once(&store_once, []() { - pthread_key_create(&store_key, [](void *ptr) { - delete reinterpret_cast<ClassDictionary *>(ptr); - }); - }); - - ClassDictionary *ptr = reinterpret_cast<ClassDictionary *>(pthread_getspecific(store_key)); - if (ptr == nullptr) { - ptr = new ClassDictionary(); - pthread_setspecific(store_key, ptr); - } - - return *ptr; -} - -ClassID ClassDictionary::lookup(const std::string &class_name) { - auto it = store.find(class_name); - if (it == store.end()) { - // Insert the class name into the store. - ClassID id = ClassID(uint32_t(ClassID::Named) + offset++); - store.emplace(class_name, id); - return id; - } else { - return it->second; - } -} - -ClassID ClassDictionary::normalize(ClassID id) { - if (id >= ClassID::Named) { - return ClassID::Named; - } else { - return id; - } -} - -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/class_dictionary.hpp b/src/mbgl/style/class_dictionary.hpp deleted file mode 100644 index 37eb488240..0000000000 --- a/src/mbgl/style/class_dictionary.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include <cstdint> -#include <string> -#include <unordered_map> -#include <functional> - -namespace mbgl { -namespace style { - -enum class ClassID : uint32_t { - Default = 1, // These values are from the default style for a layer - Named = 2 // These values (and all subsequent IDs) are from a named style from the layer -}; - -class ClassDictionary { -private: - ClassDictionary(); - -public: - static ClassDictionary &Get(); - - // Returns an ID for a class name. If the class name does not yet have an ID, one is - // auto-generated and stored for future reference. - ClassID lookup(const std::string &class_name); - - // Returns either Fallback, Default or Named, depending on the type of the class id. - ClassID normalize(ClassID id); - -private: - std::unordered_map<std::string, ClassID> store = { { "", ClassID::Default } }; - uint32_t offset = 0; -}; - -} // namespace style -} // namespace mbgl - -namespace std { - -// Explicitly define std::hash<style::ClassID> because GCC doesn't automatically use std::hash<> of -// the underlying enum type. - -template <> -struct hash<mbgl::style::ClassID> { -public: - size_t operator()(const mbgl::style::ClassID id) const { - using T = std::underlying_type_t<mbgl::style::ClassID>; - return std::hash<T>()(static_cast<T>(id)); - } -}; - -} // namespace std diff --git a/src/mbgl/style/collection.hpp b/src/mbgl/style/collection.hpp new file mode 100644 index 0000000000..0deb1411b6 --- /dev/null +++ b/src/mbgl/style/collection.hpp @@ -0,0 +1,141 @@ +#pragma once + +#include <mbgl/util/immutable.hpp> +#include <mbgl/util/optional.hpp> + +#include <memory> +#include <string> + +namespace mbgl { +namespace style { + +/* + Manages an ordered collection of elements and their `Immutable<Impl>`s. The latter is + itself stored in an Immutable container. Using immutability at the collection level + allows us to short-circuit significant portions of the RenderStyle update logic via + a simple pointer equality check, greatly improving performance. + + Element types are required to have: + + * An `Impl` inner class type + * An `Immutable<Impl> baseImpl` member + * A `std::string getID() const` method +*/ +template <class T> +class Collection { +public: + using Impl = typename T::Impl; + using WrapperVector = std::vector<std::unique_ptr<T>>; + using ImmutableVector = Immutable<std::vector<Immutable<Impl>>>; + + Collection(); + + std::size_t size() const; + T* get(const std::string&) const; + + std::vector<T*> getWrappers() const; + ImmutableVector getImpls() const { return impls; } + + auto begin() const { return wrappers.begin(); } + auto end() const { return wrappers.end(); } + + void clear(); + + T* add(std::unique_ptr<T>, const optional<std::string>& = {}); + std::unique_ptr<T> remove(const std::string&); + + // Must be called whenever an element of the collection is internally mutated. + // Typically, each element permits registration of an observer, and the observer + // should call this method. + void update(const T&); + +private: + std::size_t index(const std::string&) const; + + WrapperVector wrappers; + ImmutableVector impls; +}; + +template <class T> +Collection<T>::Collection() + : impls(makeMutable<std::vector<Immutable<Impl>>>()) { +} + +template <class T> +std::size_t Collection<T>::size() const { + return wrappers.size(); +} + +template <class T> +std::size_t Collection<T>::index(const std::string& id) const { + return std::find_if(wrappers.begin(), wrappers.end(), [&](const auto& e) { + return e->getID() == id; + }) - wrappers.begin(); +} + +template <class T> +T* Collection<T>::get(const std::string& id) const { + std::size_t i = index(id); + return i < size() ? wrappers[i].get() : nullptr; +} + +template <class T> +std::vector<T*> Collection<T>::getWrappers() const { + std::vector<T*> result; + result.reserve(wrappers.size()); + + for (auto& wrapper : wrappers) { + result.push_back(wrapper.get()); + } + + return result; +} + +template <class T> +void Collection<T>::clear() { + mutate(impls, [&] (auto& impls_) { + impls_.clear(); + }); + + wrappers.clear(); +} + +template <class T> +T* Collection<T>::add(std::unique_ptr<T> wrapper, const optional<std::string>& before) { + std::size_t i = before ? index(*before) : size(); + + mutate(impls, [&] (auto& impls_) { + impls_.emplace(impls_.begin() + i, wrapper->baseImpl); + }); + + return wrappers.emplace(wrappers.begin() + i, std::move(wrapper))->get(); +} + +template <class T> +std::unique_ptr<T> Collection<T>::remove(const std::string& id) { + std::size_t i = index(id); + + if (i >= size()) { + return nullptr; + } + + auto source = std::move(wrappers[i]); + + mutate(impls, [&] (auto& impls_) { + impls_.erase(impls_.begin() + i); + }); + + wrappers.erase(wrappers.begin() + i); + + return source; +} + +template <class T> +void Collection<T>::update(const T& wrapper) { + mutate(impls, [&] (auto& impls_) { + impls_.at(this->index(wrapper.getID())) = wrapper.baseImpl; + }); +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/stringify.hpp b/src/mbgl/style/conversion/stringify.hpp index 4afbf198e5..6ae6fede42 100644 --- a/src/mbgl/style/conversion/stringify.hpp +++ b/src/mbgl/style/conversion/stringify.hpp @@ -2,7 +2,7 @@ #include <mbgl/style/filter.hpp> #include <mbgl/style/property_value.hpp> -#include <mbgl/style/layout_property.hpp> +#include <mbgl/style/data_driven_property_value.hpp> #include <mbgl/util/enum.hpp> #include <mbgl/util/color.hpp> #include <mbgl/util/feature.hpp> @@ -446,13 +446,6 @@ void stringify(Writer& writer, const DataDrivenPropertyValue<T>& value) { } } -template <class Writer, class... Ps> -void stringify(Writer& writer, const LayoutProperties<Ps...>& ps) { - writer.StartObject(); - util::ignore({ (stringify<Ps>(writer, ps.unevaluated.template get<Ps>()), 0)... }); - writer.EndObject(); -} - } // namespace conversion } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/function/categorical_stops.cpp b/src/mbgl/style/function/categorical_stops.cpp index 2984c3832f..dd179f5376 100644 --- a/src/mbgl/style/function/categorical_stops.cpp +++ b/src/mbgl/style/function/categorical_stops.cpp @@ -33,6 +33,9 @@ template class CategoricalStops<Color>; template class CategoricalStops<std::array<float, 2>>; template class CategoricalStops<std::string>; template class CategoricalStops<TextTransformType>; +template class CategoricalStops<TextJustifyType>; +template class CategoricalStops<SymbolAnchorType>; +template class CategoricalStops<LineJoinType>; } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/function/identity_stops.cpp b/src/mbgl/style/function/identity_stops.cpp index dfb34e9dd4..0ac6fda846 100644 --- a/src/mbgl/style/function/identity_stops.cpp +++ b/src/mbgl/style/function/identity_stops.cpp @@ -36,25 +36,53 @@ optional<TextTransformType> IdentityStops<TextTransformType>::evaluate(const Val if (!value.is<std::string>()) { return {}; } - + return Enum<TextTransformType>::toEnum(value.get<std::string>()); } template <> +optional<TextJustifyType> IdentityStops<TextJustifyType>::evaluate(const Value& value) const { + if (!value.is<std::string>()) { + return {}; + } + + return Enum<TextJustifyType>::toEnum(value.get<std::string>()); +} + +template <> +optional<SymbolAnchorType> IdentityStops<SymbolAnchorType>::evaluate(const Value& value) const { + if (!value.is<std::string>()) { + return {}; + } + + return Enum<SymbolAnchorType>::toEnum(value.get<std::string>()); +} + +template <> +optional<LineJoinType> IdentityStops<LineJoinType>::evaluate(const Value& value) const { + if (!value.is<std::string>()) { + return {}; + } + + return Enum<LineJoinType>::toEnum(value.get<std::string>()); +} + +template <> optional<std::array<float, 2>> IdentityStops<std::array<float, 2>>::evaluate(const Value& value) const { if (!value.is<std::vector<Value>>()) { return {}; } - const std::vector<Value>& vector = value.get<std::vector<Value>>(); + const auto& vector = value.get<std::vector<Value>>(); if (vector.size() != 2 || !numericValue<float>(vector[0]) || !numericValue<float>(vector[1])) { return {}; } - return {{{ + std::array<float, 2> array {{ *numericValue<float>(vector[0]), *numericValue<float>(vector[1]) - }}}; + }}; + return array; } } // namespace style diff --git a/src/mbgl/style/image.cpp b/src/mbgl/style/image.cpp index 4c0c6a859b..1747de5fcc 100644 --- a/src/mbgl/style/image.cpp +++ b/src/mbgl/style/image.cpp @@ -1,21 +1,33 @@ #include <mbgl/style/image.hpp> +#include <mbgl/style/image_impl.hpp> #include <mbgl/util/exception.hpp> namespace mbgl { namespace style { -Image::Image(PremultipliedImage&& image_, - const float pixelRatio_, - bool sdf_) - : image(std::move(image_)), - pixelRatio(pixelRatio_), - sdf(sdf_) { - - if (!image.valid()) { - throw util::SpriteImageException("Sprite image dimensions may not be zero"); - } else if (pixelRatio <= 0) { - throw util::SpriteImageException("Sprite pixelRatio may not be <= 0"); - } +Image::Image(std::string id, + PremultipliedImage &&image, + const float pixelRatio, + bool sdf) + : baseImpl(makeMutable<Impl>(std::move(id), std::move(image), pixelRatio, sdf)) { +} + +std::string Image::getID() const { + return baseImpl->id; +} + +Image::Image(const Image&) = default; + +const PremultipliedImage& Image::getImage() const { + return baseImpl->image; +} + +bool Image::isSdf() const { + return baseImpl->sdf; +} + +float Image::getPixelRatio() const { + return baseImpl->pixelRatio; } } // namespace style diff --git a/src/mbgl/style/image_impl.cpp b/src/mbgl/style/image_impl.cpp new file mode 100644 index 0000000000..ce327262e8 --- /dev/null +++ b/src/mbgl/style/image_impl.cpp @@ -0,0 +1,24 @@ +#include <mbgl/style/image_impl.hpp> +#include <mbgl/util/exception.hpp> + +namespace mbgl { +namespace style { + +Image::Impl::Impl(std::string id_, + PremultipliedImage&& image_, + const float pixelRatio_, + bool sdf_) + : id(std::move(id_)), + image(std::move(image_)), + pixelRatio(pixelRatio_), + sdf(sdf_) { + + if (!image.valid()) { + throw util::SpriteImageException("Sprite image dimensions may not be zero"); + } else if (pixelRatio <= 0) { + throw util::SpriteImageException("Sprite pixelRatio may not be <= 0"); + } +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/image_impl.hpp b/src/mbgl/style/image_impl.hpp new file mode 100644 index 0000000000..e439e42695 --- /dev/null +++ b/src/mbgl/style/image_impl.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include <mbgl/style/image.hpp> + +#include <string> +#include <unordered_map> +#include <set> + +namespace mbgl { +namespace style { + +class Image::Impl { +public: + Impl(std::string id, PremultipliedImage&&, float pixelRatio, bool sdf = false); + + const std::string id; + + PremultipliedImage image; + + // Pixel ratio of the sprite image. + const float pixelRatio; + + // Whether this image should be interpreted as a signed distance field icon. + const bool sdf; +}; + +} // namespace style + +using ImageMap = std::unordered_map<std::string, Immutable<style::Image::Impl>>; +using ImageDependencies = std::set<std::string>; +using ImageRequestPair = std::pair<ImageDependencies, uint64_t>; + +} // namespace mbgl diff --git a/src/mbgl/style/layer.cpp b/src/mbgl/style/layer.cpp index e2eba0e2e0..142fe313cf 100644 --- a/src/mbgl/style/layer.cpp +++ b/src/mbgl/style/layer.cpp @@ -1,17 +1,24 @@ #include <mbgl/style/layer.hpp> #include <mbgl/style/layer_impl.hpp> -#include <mbgl/style/layer_type.hpp> +#include <mbgl/style/layer_observer.hpp> namespace mbgl { namespace style { -Layer::Layer(LayerType type_, std::unique_ptr<Impl> baseImpl_) - : type(type_), baseImpl(std::move(baseImpl_)) { +static LayerObserver nullObserver; + +Layer::Layer(Immutable<Impl> impl) + : baseImpl(std::move(impl)), + observer(&nullObserver) { } Layer::~Layer() = default; -const std::string& Layer::getID() const { +LayerType Layer::getType() const { + return baseImpl->type; +} + +std::string Layer::getID() const { return baseImpl->id; } @@ -19,27 +26,16 @@ VisibilityType Layer::getVisibility() const { return baseImpl->visibility; } -void Layer::setVisibility(VisibilityType value) { - if (value == getVisibility()) - return; - baseImpl->visibility = value; - baseImpl->observer->onLayerVisibilityChanged(*this); -} - float Layer::getMinZoom() const { return baseImpl->minZoom; } -void Layer::setMinZoom(float minZoom) const { - baseImpl->minZoom = minZoom; -} - float Layer::getMaxZoom() const { return baseImpl->maxZoom; } -void Layer::setMaxZoom(float maxZoom) const { - baseImpl->maxZoom = maxZoom; +void Layer::setObserver(LayerObserver* observer_) { + observer = observer_ ? observer_ : &nullObserver; } } // namespace style diff --git a/src/mbgl/style/layer_impl.cpp b/src/mbgl/style/layer_impl.cpp index b8eb01fe77..a9a3941f3e 100644 --- a/src/mbgl/style/layer_impl.cpp +++ b/src/mbgl/style/layer_impl.cpp @@ -3,16 +3,10 @@ namespace mbgl { namespace style { -std::unique_ptr<Layer> Layer::Impl::copy(const std::string& id_, - const std::string& source_) const { - std::unique_ptr<Layer> result = clone(); - result->baseImpl->id = id_; - result->baseImpl->source = source_; - return result; -} - -void Layer::Impl::setObserver(LayerObserver* observer_) { - observer = observer_ ? observer_ : &nullObserver; +Layer::Impl::Impl(LayerType type_, std::string layerID, std::string sourceID) + : type(type_), + id(std::move(layerID)), + source(std::move(sourceID)) { } } // namespace style diff --git a/src/mbgl/style/layer_impl.hpp b/src/mbgl/style/layer_impl.hpp index 6aa8fccaf0..f350044925 100644 --- a/src/mbgl/style/layer_impl.hpp +++ b/src/mbgl/style/layer_impl.hpp @@ -3,13 +3,10 @@ #include <mbgl/style/layer.hpp> #include <mbgl/style/types.hpp> #include <mbgl/style/filter.hpp> -#include <mbgl/style/layer_observer.hpp> -#include <mbgl/util/noncopyable.hpp> #include <rapidjson/writer.h> #include <rapidjson/stringbuffer.h> -#include <memory> #include <string> #include <limits> @@ -32,27 +29,19 @@ namespace style { */ class Layer::Impl { public: + Impl(LayerType, std::string layerID, std::string sourceID); virtual ~Impl() = default; - // Create a new layer with the specified `id` and `sourceID`. All other properties - // are copied from this layer. - std::unique_ptr<Layer> copy(const std::string& id, - const std::string& sourceID) const; - - // Create an identical copy of this layer. - virtual std::unique_ptr<Layer> clone() const = 0; + Impl& operator=(const Impl&) = delete; - // Create a layer, copying all properties except id and paint properties from this layer. - virtual std::unique_ptr<Layer> cloneRef(const std::string& id) const = 0; + // Returns true buckets if properties affecting layout have changed: i.e. filter, + // visibility, layout properties, or data-driven paint properties. + virtual bool hasLayoutDifference(const Layer::Impl&) const = 0; // Utility function for automatic layer grouping. virtual void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const = 0; - virtual std::unique_ptr<RenderLayer> createRenderLayer() const = 0; - - void setObserver(LayerObserver*); - -public: + const LayerType type; std::string id; std::string source; std::string sourceLayer; @@ -61,13 +50,8 @@ public: float maxZoom = std::numeric_limits<float>::infinity(); VisibilityType visibility = VisibilityType::Visible; - LayerObserver nullObserver; - LayerObserver* observer = &nullObserver; - protected: - Impl() = default; Impl(const Impl&) = default; - Impl& operator=(const Impl&) = delete; }; } // namespace style diff --git a/src/mbgl/style/layer_observer.hpp b/src/mbgl/style/layer_observer.hpp index 2fa1c39660..28074a65e7 100644 --- a/src/mbgl/style/layer_observer.hpp +++ b/src/mbgl/style/layer_observer.hpp @@ -9,11 +9,7 @@ class LayerObserver { public: virtual ~LayerObserver() = default; - virtual void onLayerFilterChanged(Layer&) {} - virtual void onLayerVisibilityChanged(Layer&) {} - virtual void onLayerPaintPropertyChanged(Layer&) {} - virtual void onLayerDataDrivenPaintPropertyChanged(Layer&) {} - virtual void onLayerLayoutPropertyChanged(Layer&, const char *) {} + virtual void onLayerChanged(Layer&) {} }; } // namespace style diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp index b4ffea138b..d4ead18816 100644 --- a/src/mbgl/style/layers/background_layer.cpp +++ b/src/mbgl/style/layers/background_layer.cpp @@ -2,39 +2,65 @@ #include <mbgl/style/layers/background_layer.hpp> #include <mbgl/style/layers/background_layer_impl.hpp> -#include <mbgl/style/conversion/stringify.hpp> +#include <mbgl/style/layer_observer.hpp> namespace mbgl { namespace style { BackgroundLayer::BackgroundLayer(const std::string& layerID) - : Layer(LayerType::Background, std::make_unique<Impl>()) - , impl(static_cast<Impl*>(baseImpl.get())) { - impl->id = layerID; + : Layer(makeMutable<Impl>(LayerType::Background, layerID, std::string())) { } -BackgroundLayer::BackgroundLayer(const Impl& other) - : Layer(LayerType::Background, std::make_unique<Impl>(other)) - , impl(static_cast<Impl*>(baseImpl.get())) { +BackgroundLayer::BackgroundLayer(Immutable<Impl> impl_) + : Layer(std::move(impl_)) { } BackgroundLayer::~BackgroundLayer() = default; -std::unique_ptr<Layer> BackgroundLayer::Impl::clone() const { - return std::make_unique<BackgroundLayer>(*this); +const BackgroundLayer::Impl& BackgroundLayer::impl() const { + return static_cast<const Impl&>(*baseImpl); } -std::unique_ptr<Layer> BackgroundLayer::Impl::cloneRef(const std::string& id_) const { - auto result = std::make_unique<BackgroundLayer>(*this); - result->impl->id = id_; - result->impl->cascading = BackgroundPaintProperties::Cascading(); - return std::move(result); +Mutable<BackgroundLayer::Impl> BackgroundLayer::mutableImpl() const { + return makeMutable<Impl>(impl()); +} + +std::unique_ptr<Layer> BackgroundLayer::cloneRef(const std::string& id_) const { + auto impl_ = mutableImpl(); + impl_->id = id_; + impl_->paint = BackgroundPaintProperties::Transitionable(); + return std::make_unique<BackgroundLayer>(std::move(impl_)); } void BackgroundLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const { } +// Visibility + +void BackgroundLayer::setVisibility(VisibilityType value) { + if (value == getVisibility()) + return; + auto impl_ = mutableImpl(); + impl_->visibility = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +// Zoom range + +void BackgroundLayer::setMinZoom(float minZoom) { + auto impl_ = mutableImpl(); + impl_->minZoom = minZoom; + baseImpl = std::move(impl_); +} + +void BackgroundLayer::setMaxZoom(float maxZoom) { + auto impl_ = mutableImpl(); + impl_->maxZoom = maxZoom; + baseImpl = std::move(impl_); +} + // Layout properties @@ -44,69 +70,81 @@ PropertyValue<Color> BackgroundLayer::getDefaultBackgroundColor() { return { Color::black() }; } -PropertyValue<Color> BackgroundLayer::getBackgroundColor(const optional<std::string>& klass) const { - return impl->cascading.template get<BackgroundColor>().get(klass); +PropertyValue<Color> BackgroundLayer::getBackgroundColor() const { + return impl().paint.template get<BackgroundColor>().value; } -void BackgroundLayer::setBackgroundColor(PropertyValue<Color> value, const optional<std::string>& klass) { - if (value == getBackgroundColor(klass)) +void BackgroundLayer::setBackgroundColor(PropertyValue<Color> value) { + if (value == getBackgroundColor()) return; - impl->cascading.template get<BackgroundColor>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<BackgroundColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void BackgroundLayer::setBackgroundColorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<BackgroundColor>().setTransition(value, klass); +void BackgroundLayer::setBackgroundColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<BackgroundColor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions BackgroundLayer::getBackgroundColorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<BackgroundColor>().getTransition(klass); +TransitionOptions BackgroundLayer::getBackgroundColorTransition() const { + return impl().paint.template get<BackgroundColor>().options; } PropertyValue<std::string> BackgroundLayer::getDefaultBackgroundPattern() { return { "" }; } -PropertyValue<std::string> BackgroundLayer::getBackgroundPattern(const optional<std::string>& klass) const { - return impl->cascading.template get<BackgroundPattern>().get(klass); +PropertyValue<std::string> BackgroundLayer::getBackgroundPattern() const { + return impl().paint.template get<BackgroundPattern>().value; } -void BackgroundLayer::setBackgroundPattern(PropertyValue<std::string> value, const optional<std::string>& klass) { - if (value == getBackgroundPattern(klass)) +void BackgroundLayer::setBackgroundPattern(PropertyValue<std::string> value) { + if (value == getBackgroundPattern()) return; - impl->cascading.template get<BackgroundPattern>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<BackgroundPattern>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void BackgroundLayer::setBackgroundPatternTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<BackgroundPattern>().setTransition(value, klass); +void BackgroundLayer::setBackgroundPatternTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<BackgroundPattern>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions BackgroundLayer::getBackgroundPatternTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<BackgroundPattern>().getTransition(klass); +TransitionOptions BackgroundLayer::getBackgroundPatternTransition() const { + return impl().paint.template get<BackgroundPattern>().options; } PropertyValue<float> BackgroundLayer::getDefaultBackgroundOpacity() { return { 1 }; } -PropertyValue<float> BackgroundLayer::getBackgroundOpacity(const optional<std::string>& klass) const { - return impl->cascading.template get<BackgroundOpacity>().get(klass); +PropertyValue<float> BackgroundLayer::getBackgroundOpacity() const { + return impl().paint.template get<BackgroundOpacity>().value; } -void BackgroundLayer::setBackgroundOpacity(PropertyValue<float> value, const optional<std::string>& klass) { - if (value == getBackgroundOpacity(klass)) +void BackgroundLayer::setBackgroundOpacity(PropertyValue<float> value) { + if (value == getBackgroundOpacity()) return; - impl->cascading.template get<BackgroundOpacity>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<BackgroundOpacity>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void BackgroundLayer::setBackgroundOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<BackgroundOpacity>().setTransition(value, klass); +void BackgroundLayer::setBackgroundOpacityTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<BackgroundOpacity>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions BackgroundLayer::getBackgroundOpacityTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<BackgroundOpacity>().getTransition(klass); +TransitionOptions BackgroundLayer::getBackgroundOpacityTransition() const { + return impl().paint.template get<BackgroundOpacity>().options; } } // namespace style diff --git a/src/mbgl/style/layers/background_layer_impl.cpp b/src/mbgl/style/layers/background_layer_impl.cpp index 6c4a4c26d9..a59a84fbe9 100644 --- a/src/mbgl/style/layers/background_layer_impl.cpp +++ b/src/mbgl/style/layers/background_layer_impl.cpp @@ -1,11 +1,10 @@ #include <mbgl/style/layers/background_layer_impl.hpp> -#include <mbgl/renderer/render_background_layer.hpp> namespace mbgl { namespace style { -std::unique_ptr<RenderLayer> BackgroundLayer::Impl::createRenderLayer() const { - return std::make_unique<RenderBackgroundLayer>(*this); +bool BackgroundLayer::Impl::hasLayoutDifference(const Layer::Impl&) const { + return false; } } // namespace style diff --git a/src/mbgl/style/layers/background_layer_impl.hpp b/src/mbgl/style/layers/background_layer_impl.hpp index 85152da4ec..248a751027 100644 --- a/src/mbgl/style/layers/background_layer_impl.hpp +++ b/src/mbgl/style/layers/background_layer_impl.hpp @@ -9,13 +9,12 @@ namespace style { class BackgroundLayer::Impl : public Layer::Impl { public: - std::unique_ptr<Layer> clone() const override; - std::unique_ptr<Layer> cloneRef(const std::string& id) const override; - void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; + using Layer::Impl::Impl; - std::unique_ptr<RenderLayer> createRenderLayer() const override; + bool hasLayoutDifference(const Layer::Impl&) const override; + void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; - BackgroundPaintProperties::Cascading cascading; + BackgroundPaintProperties::Transitionable paint; }; } // namespace style diff --git a/src/mbgl/style/layers/background_layer_properties.hpp b/src/mbgl/style/layers/background_layer_properties.hpp index fae6c26a4b..3a61392fb4 100644 --- a/src/mbgl/style/layers/background_layer_properties.hpp +++ b/src/mbgl/style/layers/background_layer_properties.hpp @@ -5,7 +5,9 @@ #include <mbgl/style/types.hpp> #include <mbgl/style/layout_property.hpp> #include <mbgl/style/paint_property.hpp> +#include <mbgl/style/properties.hpp> #include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> namespace mbgl { namespace style { @@ -22,7 +24,7 @@ struct BackgroundOpacity : PaintProperty<float> { static float defaultValue() { return 1; } }; -class BackgroundPaintProperties : public PaintProperties< +class BackgroundPaintProperties : public Properties< BackgroundColor, BackgroundPattern, BackgroundOpacity diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index 8b3431a9a1..9854932699 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -2,34 +2,34 @@ #include <mbgl/style/layers/circle_layer.hpp> #include <mbgl/style/layers/circle_layer_impl.hpp> -#include <mbgl/style/conversion/stringify.hpp> +#include <mbgl/style/layer_observer.hpp> namespace mbgl { namespace style { CircleLayer::CircleLayer(const std::string& layerID, const std::string& sourceID) - : Layer(LayerType::Circle, std::make_unique<Impl>()) - , impl(static_cast<Impl*>(baseImpl.get())) { - impl->id = layerID; - impl->source = sourceID; + : Layer(makeMutable<Impl>(LayerType::Circle, layerID, sourceID)) { } -CircleLayer::CircleLayer(const Impl& other) - : Layer(LayerType::Circle, std::make_unique<Impl>(other)) - , impl(static_cast<Impl*>(baseImpl.get())) { +CircleLayer::CircleLayer(Immutable<Impl> impl_) + : Layer(std::move(impl_)) { } CircleLayer::~CircleLayer() = default; -std::unique_ptr<Layer> CircleLayer::Impl::clone() const { - return std::make_unique<CircleLayer>(*this); +const CircleLayer::Impl& CircleLayer::impl() const { + return static_cast<const Impl&>(*baseImpl); } -std::unique_ptr<Layer> CircleLayer::Impl::cloneRef(const std::string& id_) const { - auto result = std::make_unique<CircleLayer>(*this); - result->impl->id = id_; - result->impl->cascading = CirclePaintProperties::Cascading(); - return std::move(result); +Mutable<CircleLayer::Impl> CircleLayer::mutableImpl() const { + return makeMutable<Impl>(impl()); +} + +std::unique_ptr<Layer> CircleLayer::cloneRef(const std::string& id_) const { + auto impl_ = mutableImpl(); + impl_->id = id_; + impl_->paint = CirclePaintProperties::Transitionable(); + return std::make_unique<CircleLayer>(std::move(impl_)); } void CircleLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const { @@ -38,26 +38,55 @@ void CircleLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffe // Source const std::string& CircleLayer::getSourceID() const { - return impl->source; + return impl().source; } void CircleLayer::setSourceLayer(const std::string& sourceLayer) { - impl->sourceLayer = sourceLayer; + auto impl_ = mutableImpl(); + impl_->sourceLayer = sourceLayer; + baseImpl = std::move(impl_); } const std::string& CircleLayer::getSourceLayer() const { - return impl->sourceLayer; + return impl().sourceLayer; } // Filter void CircleLayer::setFilter(const Filter& filter) { - impl->filter = filter; - impl->observer->onLayerFilterChanged(*this); + auto impl_ = mutableImpl(); + impl_->filter = filter; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } const Filter& CircleLayer::getFilter() const { - return impl->filter; + return impl().filter; +} + +// Visibility + +void CircleLayer::setVisibility(VisibilityType value) { + if (value == getVisibility()) + return; + auto impl_ = mutableImpl(); + impl_->visibility = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +// Zoom range + +void CircleLayer::setMinZoom(float minZoom) { + auto impl_ = mutableImpl(); + impl_->minZoom = minZoom; + baseImpl = std::move(impl_); +} + +void CircleLayer::setMaxZoom(float maxZoom) { + auto impl_ = mutableImpl(); + impl_->maxZoom = maxZoom; + baseImpl = std::move(impl_); } // Layout properties @@ -69,258 +98,297 @@ DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleRadius() { return { 5 }; } -DataDrivenPropertyValue<float> CircleLayer::getCircleRadius(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleRadius>().get(klass); +DataDrivenPropertyValue<float> CircleLayer::getCircleRadius() const { + return impl().paint.template get<CircleRadius>().value; } -void CircleLayer::setCircleRadius(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getCircleRadius(klass)) +void CircleLayer::setCircleRadius(DataDrivenPropertyValue<float> value) { + if (value == getCircleRadius()) return; - impl->cascading.template get<CircleRadius>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleRadius>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void CircleLayer::setCircleRadiusTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<CircleRadius>().setTransition(value, klass); +void CircleLayer::setCircleRadiusTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleRadius>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions CircleLayer::getCircleRadiusTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleRadius>().getTransition(klass); +TransitionOptions CircleLayer::getCircleRadiusTransition() const { + return impl().paint.template get<CircleRadius>().options; } DataDrivenPropertyValue<Color> CircleLayer::getDefaultCircleColor() { return { Color::black() }; } -DataDrivenPropertyValue<Color> CircleLayer::getCircleColor(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleColor>().get(klass); +DataDrivenPropertyValue<Color> CircleLayer::getCircleColor() const { + return impl().paint.template get<CircleColor>().value; } -void CircleLayer::setCircleColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { - if (value == getCircleColor(klass)) +void CircleLayer::setCircleColor(DataDrivenPropertyValue<Color> value) { + if (value == getCircleColor()) return; - impl->cascading.template get<CircleColor>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void CircleLayer::setCircleColorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<CircleColor>().setTransition(value, klass); +void CircleLayer::setCircleColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleColor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions CircleLayer::getCircleColorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleColor>().getTransition(klass); +TransitionOptions CircleLayer::getCircleColorTransition() const { + return impl().paint.template get<CircleColor>().options; } DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleBlur() { return { 0 }; } -DataDrivenPropertyValue<float> CircleLayer::getCircleBlur(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleBlur>().get(klass); +DataDrivenPropertyValue<float> CircleLayer::getCircleBlur() const { + return impl().paint.template get<CircleBlur>().value; } -void CircleLayer::setCircleBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getCircleBlur(klass)) +void CircleLayer::setCircleBlur(DataDrivenPropertyValue<float> value) { + if (value == getCircleBlur()) return; - impl->cascading.template get<CircleBlur>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleBlur>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void CircleLayer::setCircleBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<CircleBlur>().setTransition(value, klass); +void CircleLayer::setCircleBlurTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleBlur>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions CircleLayer::getCircleBlurTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleBlur>().getTransition(klass); +TransitionOptions CircleLayer::getCircleBlurTransition() const { + return impl().paint.template get<CircleBlur>().options; } DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleOpacity() { return { 1 }; } -DataDrivenPropertyValue<float> CircleLayer::getCircleOpacity(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleOpacity>().get(klass); +DataDrivenPropertyValue<float> CircleLayer::getCircleOpacity() const { + return impl().paint.template get<CircleOpacity>().value; } -void CircleLayer::setCircleOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getCircleOpacity(klass)) +void CircleLayer::setCircleOpacity(DataDrivenPropertyValue<float> value) { + if (value == getCircleOpacity()) return; - impl->cascading.template get<CircleOpacity>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleOpacity>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void CircleLayer::setCircleOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<CircleOpacity>().setTransition(value, klass); +void CircleLayer::setCircleOpacityTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleOpacity>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions CircleLayer::getCircleOpacityTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleOpacity>().getTransition(klass); +TransitionOptions CircleLayer::getCircleOpacityTransition() const { + return impl().paint.template get<CircleOpacity>().options; } PropertyValue<std::array<float, 2>> CircleLayer::getDefaultCircleTranslate() { return { {{ 0, 0 }} }; } -PropertyValue<std::array<float, 2>> CircleLayer::getCircleTranslate(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleTranslate>().get(klass); +PropertyValue<std::array<float, 2>> CircleLayer::getCircleTranslate() const { + return impl().paint.template get<CircleTranslate>().value; } -void CircleLayer::setCircleTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) { - if (value == getCircleTranslate(klass)) +void CircleLayer::setCircleTranslate(PropertyValue<std::array<float, 2>> value) { + if (value == getCircleTranslate()) return; - impl->cascading.template get<CircleTranslate>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleTranslate>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void CircleLayer::setCircleTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<CircleTranslate>().setTransition(value, klass); +void CircleLayer::setCircleTranslateTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleTranslate>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions CircleLayer::getCircleTranslateTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleTranslate>().getTransition(klass); +TransitionOptions CircleLayer::getCircleTranslateTransition() const { + return impl().paint.template get<CircleTranslate>().options; } PropertyValue<TranslateAnchorType> CircleLayer::getDefaultCircleTranslateAnchor() { return { TranslateAnchorType::Map }; } -PropertyValue<TranslateAnchorType> CircleLayer::getCircleTranslateAnchor(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleTranslateAnchor>().get(klass); +PropertyValue<TranslateAnchorType> CircleLayer::getCircleTranslateAnchor() const { + return impl().paint.template get<CircleTranslateAnchor>().value; } -void CircleLayer::setCircleTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) { - if (value == getCircleTranslateAnchor(klass)) +void CircleLayer::setCircleTranslateAnchor(PropertyValue<TranslateAnchorType> value) { + if (value == getCircleTranslateAnchor()) return; - impl->cascading.template get<CircleTranslateAnchor>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleTranslateAnchor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void CircleLayer::setCircleTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<CircleTranslateAnchor>().setTransition(value, klass); +void CircleLayer::setCircleTranslateAnchorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleTranslateAnchor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions CircleLayer::getCircleTranslateAnchorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleTranslateAnchor>().getTransition(klass); +TransitionOptions CircleLayer::getCircleTranslateAnchorTransition() const { + return impl().paint.template get<CircleTranslateAnchor>().options; } PropertyValue<CirclePitchScaleType> CircleLayer::getDefaultCirclePitchScale() { return { CirclePitchScaleType::Map }; } -PropertyValue<CirclePitchScaleType> CircleLayer::getCirclePitchScale(const optional<std::string>& klass) const { - return impl->cascading.template get<CirclePitchScale>().get(klass); +PropertyValue<CirclePitchScaleType> CircleLayer::getCirclePitchScale() const { + return impl().paint.template get<CirclePitchScale>().value; +} + +void CircleLayer::setCirclePitchScale(PropertyValue<CirclePitchScaleType> value) { + if (value == getCirclePitchScale()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<CirclePitchScale>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void CircleLayer::setCirclePitchScaleTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<CirclePitchScale>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions CircleLayer::getCirclePitchScaleTransition() const { + return impl().paint.template get<CirclePitchScale>().options; +} + +PropertyValue<AlignmentType> CircleLayer::getDefaultCirclePitchAlignment() { + return { AlignmentType::Viewport }; +} + +PropertyValue<AlignmentType> CircleLayer::getCirclePitchAlignment() const { + return impl().paint.template get<CirclePitchAlignment>().value; } -void CircleLayer::setCirclePitchScale(PropertyValue<CirclePitchScaleType> value, const optional<std::string>& klass) { - if (value == getCirclePitchScale(klass)) +void CircleLayer::setCirclePitchAlignment(PropertyValue<AlignmentType> value) { + if (value == getCirclePitchAlignment()) return; - impl->cascading.template get<CirclePitchScale>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<CirclePitchAlignment>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void CircleLayer::setCirclePitchScaleTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<CirclePitchScale>().setTransition(value, klass); +void CircleLayer::setCirclePitchAlignmentTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<CirclePitchAlignment>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions CircleLayer::getCirclePitchScaleTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<CirclePitchScale>().getTransition(klass); +TransitionOptions CircleLayer::getCirclePitchAlignmentTransition() const { + return impl().paint.template get<CirclePitchAlignment>().options; } DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleStrokeWidth() { return { 0 }; } -DataDrivenPropertyValue<float> CircleLayer::getCircleStrokeWidth(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleStrokeWidth>().get(klass); +DataDrivenPropertyValue<float> CircleLayer::getCircleStrokeWidth() const { + return impl().paint.template get<CircleStrokeWidth>().value; } -void CircleLayer::setCircleStrokeWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getCircleStrokeWidth(klass)) +void CircleLayer::setCircleStrokeWidth(DataDrivenPropertyValue<float> value) { + if (value == getCircleStrokeWidth()) return; - impl->cascading.template get<CircleStrokeWidth>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleStrokeWidth>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void CircleLayer::setCircleStrokeWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<CircleStrokeWidth>().setTransition(value, klass); +void CircleLayer::setCircleStrokeWidthTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleStrokeWidth>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions CircleLayer::getCircleStrokeWidthTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleStrokeWidth>().getTransition(klass); +TransitionOptions CircleLayer::getCircleStrokeWidthTransition() const { + return impl().paint.template get<CircleStrokeWidth>().options; } DataDrivenPropertyValue<Color> CircleLayer::getDefaultCircleStrokeColor() { return { Color::black() }; } -DataDrivenPropertyValue<Color> CircleLayer::getCircleStrokeColor(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleStrokeColor>().get(klass); +DataDrivenPropertyValue<Color> CircleLayer::getCircleStrokeColor() const { + return impl().paint.template get<CircleStrokeColor>().value; } -void CircleLayer::setCircleStrokeColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { - if (value == getCircleStrokeColor(klass)) +void CircleLayer::setCircleStrokeColor(DataDrivenPropertyValue<Color> value) { + if (value == getCircleStrokeColor()) return; - impl->cascading.template get<CircleStrokeColor>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleStrokeColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void CircleLayer::setCircleStrokeColorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<CircleStrokeColor>().setTransition(value, klass); +void CircleLayer::setCircleStrokeColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleStrokeColor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions CircleLayer::getCircleStrokeColorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleStrokeColor>().getTransition(klass); +TransitionOptions CircleLayer::getCircleStrokeColorTransition() const { + return impl().paint.template get<CircleStrokeColor>().options; } DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleStrokeOpacity() { return { 1 }; } -DataDrivenPropertyValue<float> CircleLayer::getCircleStrokeOpacity(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleStrokeOpacity>().get(klass); +DataDrivenPropertyValue<float> CircleLayer::getCircleStrokeOpacity() const { + return impl().paint.template get<CircleStrokeOpacity>().value; } -void CircleLayer::setCircleStrokeOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getCircleStrokeOpacity(klass)) +void CircleLayer::setCircleStrokeOpacity(DataDrivenPropertyValue<float> value) { + if (value == getCircleStrokeOpacity()) return; - impl->cascading.template get<CircleStrokeOpacity>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleStrokeOpacity>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void CircleLayer::setCircleStrokeOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<CircleStrokeOpacity>().setTransition(value, klass); +void CircleLayer::setCircleStrokeOpacityTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<CircleStrokeOpacity>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions CircleLayer::getCircleStrokeOpacityTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<CircleStrokeOpacity>().getTransition(klass); +TransitionOptions CircleLayer::getCircleStrokeOpacityTransition() const { + return impl().paint.template get<CircleStrokeOpacity>().options; } } // namespace style diff --git a/src/mbgl/style/layers/circle_layer_impl.cpp b/src/mbgl/style/layers/circle_layer_impl.cpp index 31b286f273..69f574cd6b 100644 --- a/src/mbgl/style/layers/circle_layer_impl.cpp +++ b/src/mbgl/style/layers/circle_layer_impl.cpp @@ -1,11 +1,14 @@ #include <mbgl/style/layers/circle_layer_impl.hpp> -#include <mbgl/renderer/render_circle_layer.hpp> namespace mbgl { namespace style { -std::unique_ptr<RenderLayer> CircleLayer::Impl::createRenderLayer() const { - return std::make_unique<RenderCircleLayer>(*this); +bool CircleLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const { + assert(dynamic_cast<const CircleLayer::Impl*>(&other)); + const auto& impl = static_cast<const style::CircleLayer::Impl&>(other); + return filter != impl.filter || + visibility != impl.visibility || + paint.hasDataDrivenPropertyDifference(impl.paint); } } // namespace style diff --git a/src/mbgl/style/layers/circle_layer_impl.hpp b/src/mbgl/style/layers/circle_layer_impl.hpp index 886815f0d1..4b148cdc42 100644 --- a/src/mbgl/style/layers/circle_layer_impl.hpp +++ b/src/mbgl/style/layers/circle_layer_impl.hpp @@ -9,13 +9,12 @@ namespace style { class CircleLayer::Impl : public Layer::Impl { public: - std::unique_ptr<Layer> clone() const override; - std::unique_ptr<Layer> cloneRef(const std::string& id) const override; - void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; + using Layer::Impl::Impl; - std::unique_ptr<RenderLayer> createRenderLayer() const override; + bool hasLayoutDifference(const Layer::Impl&) const override; + void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; - CirclePaintProperties::Cascading cascading; + CirclePaintProperties::Transitionable paint; }; } // namespace style diff --git a/src/mbgl/style/layers/circle_layer_properties.hpp b/src/mbgl/style/layers/circle_layer_properties.hpp index 58206c61da..bc0c961e75 100644 --- a/src/mbgl/style/layers/circle_layer_properties.hpp +++ b/src/mbgl/style/layers/circle_layer_properties.hpp @@ -5,6 +5,7 @@ #include <mbgl/style/types.hpp> #include <mbgl/style/layout_property.hpp> #include <mbgl/style/paint_property.hpp> +#include <mbgl/style/properties.hpp> #include <mbgl/programs/attributes.hpp> #include <mbgl/programs/uniforms.hpp> @@ -39,6 +40,10 @@ struct CirclePitchScale : PaintProperty<CirclePitchScaleType> { static CirclePitchScaleType defaultValue() { return CirclePitchScaleType::Map; } }; +struct CirclePitchAlignment : PaintProperty<AlignmentType> { + static AlignmentType defaultValue() { return AlignmentType::Viewport; } +}; + struct CircleStrokeWidth : DataDrivenPaintProperty<float, attributes::a_stroke_width, uniforms::u_stroke_width> { static float defaultValue() { return 0; } }; @@ -51,7 +56,7 @@ struct CircleStrokeOpacity : DataDrivenPaintProperty<float, attributes::a_stroke static float defaultValue() { return 1; } }; -class CirclePaintProperties : public PaintProperties< +class CirclePaintProperties : public Properties< CircleRadius, CircleColor, CircleBlur, @@ -59,6 +64,7 @@ class CirclePaintProperties : public PaintProperties< CircleTranslate, CircleTranslateAnchor, CirclePitchScale, + CirclePitchAlignment, CircleStrokeWidth, CircleStrokeColor, CircleStrokeOpacity diff --git a/src/mbgl/style/layers/custom_layer.cpp b/src/mbgl/style/layers/custom_layer.cpp index cda8a157f0..854c771847 100644 --- a/src/mbgl/style/layers/custom_layer.cpp +++ b/src/mbgl/style/layers/custom_layer.cpp @@ -1,6 +1,6 @@ #include <mbgl/style/layers/custom_layer.hpp> #include <mbgl/style/layers/custom_layer_impl.hpp> -#include <mbgl/util/logging.hpp> +#include <mbgl/style/layer_observer.hpp> namespace mbgl { namespace style { @@ -8,23 +8,63 @@ namespace style { CustomLayer::CustomLayer(const std::string& layerID, CustomLayerInitializeFunction init, CustomLayerRenderFunction render, + CustomLayerContextLostFunction contextLost, CustomLayerDeinitializeFunction deinit, void* context) - : Layer(LayerType::Custom, std::make_unique<Impl>(layerID, init, render, deinit, context)) - , impl(static_cast<Impl*>(baseImpl.get())) { - Log::Info(Event::General, "New custom layer: %s", layerID.c_str()); + : Layer(makeMutable<Impl>(layerID, init, render, contextLost, deinit, context)) { } -CustomLayer::CustomLayer(const Impl& other) - : Layer(LayerType::Custom, std::make_unique<Impl>(other)) - , impl(static_cast<Impl*>(baseImpl.get())) { +CustomLayer::CustomLayer(const std::string& layerID, + CustomLayerInitializeFunction init, + CustomLayerRenderFunction render, + CustomLayerDeinitializeFunction deinit, + void* context) + : Layer(makeMutable<Impl>(layerID, init, render, nullptr, deinit, context)) { } CustomLayer::~CustomLayer() = default; +const CustomLayer::Impl& CustomLayer::impl() const { + return static_cast<const Impl&>(*baseImpl); +} + +Mutable<CustomLayer::Impl> CustomLayer::mutableImpl() const { + return makeMutable<Impl>(impl()); +} + +std::unique_ptr<Layer> CustomLayer::cloneRef(const std::string&) const { + assert(false); + return nullptr; +} + +// Visibility + +void CustomLayer::setVisibility(VisibilityType value) { + if (value == getVisibility()) + return; + auto impl_ = mutableImpl(); + impl_->visibility = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +// Zoom range + +void CustomLayer::setMinZoom(float minZoom) { + auto impl_ = mutableImpl(); + impl_->minZoom = minZoom; + baseImpl = std::move(impl_); +} + +void CustomLayer::setMaxZoom(float maxZoom) { + auto impl_ = mutableImpl(); + impl_->maxZoom = maxZoom; + baseImpl = std::move(impl_); +} + template <> bool Layer::is<CustomLayer>() const { - return type == LayerType::Custom; + return getType() == LayerType::Custom; } } // namespace style diff --git a/src/mbgl/style/layers/custom_layer_impl.cpp b/src/mbgl/style/layers/custom_layer_impl.cpp index 1d3e9af8d6..1de268d2e2 100644 --- a/src/mbgl/style/layers/custom_layer_impl.cpp +++ b/src/mbgl/style/layers/custom_layer_impl.cpp @@ -1,74 +1,28 @@ #include <mbgl/style/layers/custom_layer_impl.hpp> -#include <mbgl/renderer/render_custom_layer.hpp> -#include <mbgl/map/transform_state.hpp> -#include <mbgl/util/logging.hpp> + namespace mbgl { namespace style { -std::unique_ptr<RenderLayer> CustomLayer::Impl::createRenderLayer() const { - return std::make_unique<RenderCustomLayer>(*this); -} - CustomLayer::Impl::Impl(const std::string& id_, CustomLayerInitializeFunction initializeFn_, CustomLayerRenderFunction renderFn_, + CustomLayerContextLostFunction contextLostFn_, CustomLayerDeinitializeFunction deinitializeFn_, - void* context_) { - Log::Info(Event::General, "New custom layer Impl: %s", id_.c_str()); - id = id_; + void* context_) + : Layer::Impl(LayerType::Custom, id_, std::string()) { initializeFn = initializeFn_; renderFn = renderFn_; deinitializeFn = deinitializeFn_; + contextLostFn = contextLostFn_; context = context_; } -CustomLayer::Impl::Impl(const CustomLayer::Impl &other) - : Layer::Impl(other) { - id = other.id; - // Don't copy anything else. -} - -CustomLayer::Impl::~Impl() = default; - -std::unique_ptr<Layer> CustomLayer::Impl::clone() const { - return std::make_unique<CustomLayer>(*this); -} - -std::unique_ptr<Layer> CustomLayer::Impl::cloneRef(const std::string&) const { - assert(false); - return std::make_unique<CustomLayer>(*this); +bool CustomLayer::Impl::hasLayoutDifference(const Layer::Impl&) const { + return false; } void CustomLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const { } -void CustomLayer::Impl::initialize() { - assert(initializeFn); - initializeFn(context); -} - -void CustomLayer::Impl::deinitialize() { - if (deinitializeFn) { - deinitializeFn(context); - } -} - -void CustomLayer::Impl::render(const TransformState& state) const { - assert(renderFn); - - CustomLayerRenderParameters parameters; - - parameters.width = state.getSize().width; - parameters.height = state.getSize().height; - parameters.latitude = state.getLatLng().latitude(); - parameters.longitude = state.getLatLng().longitude(); - parameters.zoom = state.getZoom(); - parameters.bearing = -state.getAngle() * util::RAD2DEG; - parameters.pitch = state.getPitch(); - parameters.fieldOfView = state.getFieldOfView(); - - renderFn(context, parameters); -} - } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/custom_layer_impl.hpp b/src/mbgl/style/layers/custom_layer_impl.hpp index e612d17f14..62efbbe15b 100644 --- a/src/mbgl/style/layers/custom_layer_impl.hpp +++ b/src/mbgl/style/layers/custom_layer_impl.hpp @@ -14,25 +14,16 @@ public: Impl(const std::string& id, CustomLayerInitializeFunction, CustomLayerRenderFunction, + CustomLayerContextLostFunction, CustomLayerDeinitializeFunction, void* context); - Impl(const Impl&); - ~Impl() final; - - void initialize(); - void deinitialize(); - void render(const TransformState&) const; - -private: - std::unique_ptr<Layer> clone() const override; - std::unique_ptr<Layer> cloneRef(const std::string& id) const override; + bool hasLayoutDifference(const Layer::Impl&) const override; void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; - std::unique_ptr<RenderLayer> createRenderLayer() const final; - CustomLayerInitializeFunction initializeFn = nullptr; CustomLayerRenderFunction renderFn = nullptr; + CustomLayerContextLostFunction contextLostFn = nullptr; CustomLayerDeinitializeFunction deinitializeFn = nullptr; void* context = nullptr; }; diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp index 6f11d6052c..62f92cef75 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp @@ -2,34 +2,34 @@ #include <mbgl/style/layers/fill_extrusion_layer.hpp> #include <mbgl/style/layers/fill_extrusion_layer_impl.hpp> -#include <mbgl/style/conversion/stringify.hpp> +#include <mbgl/style/layer_observer.hpp> namespace mbgl { namespace style { FillExtrusionLayer::FillExtrusionLayer(const std::string& layerID, const std::string& sourceID) - : Layer(LayerType::FillExtrusion, std::make_unique<Impl>()) - , impl(static_cast<Impl*>(baseImpl.get())) { - impl->id = layerID; - impl->source = sourceID; + : Layer(makeMutable<Impl>(LayerType::FillExtrusion, layerID, sourceID)) { } -FillExtrusionLayer::FillExtrusionLayer(const Impl& other) - : Layer(LayerType::FillExtrusion, std::make_unique<Impl>(other)) - , impl(static_cast<Impl*>(baseImpl.get())) { +FillExtrusionLayer::FillExtrusionLayer(Immutable<Impl> impl_) + : Layer(std::move(impl_)) { } FillExtrusionLayer::~FillExtrusionLayer() = default; -std::unique_ptr<Layer> FillExtrusionLayer::Impl::clone() const { - return std::make_unique<FillExtrusionLayer>(*this); +const FillExtrusionLayer::Impl& FillExtrusionLayer::impl() const { + return static_cast<const Impl&>(*baseImpl); } -std::unique_ptr<Layer> FillExtrusionLayer::Impl::cloneRef(const std::string& id_) const { - auto result = std::make_unique<FillExtrusionLayer>(*this); - result->impl->id = id_; - result->impl->cascading = FillExtrusionPaintProperties::Cascading(); - return std::move(result); +Mutable<FillExtrusionLayer::Impl> FillExtrusionLayer::mutableImpl() const { + return makeMutable<Impl>(impl()); +} + +std::unique_ptr<Layer> FillExtrusionLayer::cloneRef(const std::string& id_) const { + auto impl_ = mutableImpl(); + impl_->id = id_; + impl_->paint = FillExtrusionPaintProperties::Transitionable(); + return std::make_unique<FillExtrusionLayer>(std::move(impl_)); } void FillExtrusionLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const { @@ -38,26 +38,55 @@ void FillExtrusionLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::Stri // Source const std::string& FillExtrusionLayer::getSourceID() const { - return impl->source; + return impl().source; } void FillExtrusionLayer::setSourceLayer(const std::string& sourceLayer) { - impl->sourceLayer = sourceLayer; + auto impl_ = mutableImpl(); + impl_->sourceLayer = sourceLayer; + baseImpl = std::move(impl_); } const std::string& FillExtrusionLayer::getSourceLayer() const { - return impl->sourceLayer; + return impl().sourceLayer; } // Filter void FillExtrusionLayer::setFilter(const Filter& filter) { - impl->filter = filter; - impl->observer->onLayerFilterChanged(*this); + auto impl_ = mutableImpl(); + impl_->filter = filter; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } const Filter& FillExtrusionLayer::getFilter() const { - return impl->filter; + return impl().filter; +} + +// Visibility + +void FillExtrusionLayer::setVisibility(VisibilityType value) { + if (value == getVisibility()) + return; + auto impl_ = mutableImpl(); + impl_->visibility = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +// Zoom range + +void FillExtrusionLayer::setMinZoom(float minZoom) { + auto impl_ = mutableImpl(); + impl_->minZoom = minZoom; + baseImpl = std::move(impl_); +} + +void FillExtrusionLayer::setMaxZoom(float maxZoom) { + auto impl_ = mutableImpl(); + impl_->maxZoom = maxZoom; + baseImpl = std::move(impl_); } // Layout properties @@ -69,173 +98,189 @@ PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionOpacity() { return { 1 }; } -PropertyValue<float> FillExtrusionLayer::getFillExtrusionOpacity(const optional<std::string>& klass) const { - return impl->cascading.template get<FillExtrusionOpacity>().get(klass); +PropertyValue<float> FillExtrusionLayer::getFillExtrusionOpacity() const { + return impl().paint.template get<FillExtrusionOpacity>().value; } -void FillExtrusionLayer::setFillExtrusionOpacity(PropertyValue<float> value, const optional<std::string>& klass) { - if (value == getFillExtrusionOpacity(klass)) +void FillExtrusionLayer::setFillExtrusionOpacity(PropertyValue<float> value) { + if (value == getFillExtrusionOpacity()) return; - impl->cascading.template get<FillExtrusionOpacity>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<FillExtrusionOpacity>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void FillExtrusionLayer::setFillExtrusionOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<FillExtrusionOpacity>().setTransition(value, klass); +void FillExtrusionLayer::setFillExtrusionOpacityTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<FillExtrusionOpacity>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions FillExtrusionLayer::getFillExtrusionOpacityTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<FillExtrusionOpacity>().getTransition(klass); +TransitionOptions FillExtrusionLayer::getFillExtrusionOpacityTransition() const { + return impl().paint.template get<FillExtrusionOpacity>().options; } DataDrivenPropertyValue<Color> FillExtrusionLayer::getDefaultFillExtrusionColor() { return { Color::black() }; } -DataDrivenPropertyValue<Color> FillExtrusionLayer::getFillExtrusionColor(const optional<std::string>& klass) const { - return impl->cascading.template get<FillExtrusionColor>().get(klass); +DataDrivenPropertyValue<Color> FillExtrusionLayer::getFillExtrusionColor() const { + return impl().paint.template get<FillExtrusionColor>().value; } -void FillExtrusionLayer::setFillExtrusionColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { - if (value == getFillExtrusionColor(klass)) +void FillExtrusionLayer::setFillExtrusionColor(DataDrivenPropertyValue<Color> value) { + if (value == getFillExtrusionColor()) return; - impl->cascading.template get<FillExtrusionColor>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<FillExtrusionColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void FillExtrusionLayer::setFillExtrusionColorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<FillExtrusionColor>().setTransition(value, klass); +void FillExtrusionLayer::setFillExtrusionColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<FillExtrusionColor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions FillExtrusionLayer::getFillExtrusionColorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<FillExtrusionColor>().getTransition(klass); +TransitionOptions FillExtrusionLayer::getFillExtrusionColorTransition() const { + return impl().paint.template get<FillExtrusionColor>().options; } PropertyValue<std::array<float, 2>> FillExtrusionLayer::getDefaultFillExtrusionTranslate() { return { {{ 0, 0 }} }; } -PropertyValue<std::array<float, 2>> FillExtrusionLayer::getFillExtrusionTranslate(const optional<std::string>& klass) const { - return impl->cascading.template get<FillExtrusionTranslate>().get(klass); +PropertyValue<std::array<float, 2>> FillExtrusionLayer::getFillExtrusionTranslate() const { + return impl().paint.template get<FillExtrusionTranslate>().value; } -void FillExtrusionLayer::setFillExtrusionTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) { - if (value == getFillExtrusionTranslate(klass)) +void FillExtrusionLayer::setFillExtrusionTranslate(PropertyValue<std::array<float, 2>> value) { + if (value == getFillExtrusionTranslate()) return; - impl->cascading.template get<FillExtrusionTranslate>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<FillExtrusionTranslate>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void FillExtrusionLayer::setFillExtrusionTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<FillExtrusionTranslate>().setTransition(value, klass); +void FillExtrusionLayer::setFillExtrusionTranslateTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<FillExtrusionTranslate>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions FillExtrusionLayer::getFillExtrusionTranslateTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<FillExtrusionTranslate>().getTransition(klass); +TransitionOptions FillExtrusionLayer::getFillExtrusionTranslateTransition() const { + return impl().paint.template get<FillExtrusionTranslate>().options; } PropertyValue<TranslateAnchorType> FillExtrusionLayer::getDefaultFillExtrusionTranslateAnchor() { return { TranslateAnchorType::Map }; } -PropertyValue<TranslateAnchorType> FillExtrusionLayer::getFillExtrusionTranslateAnchor(const optional<std::string>& klass) const { - return impl->cascading.template get<FillExtrusionTranslateAnchor>().get(klass); +PropertyValue<TranslateAnchorType> FillExtrusionLayer::getFillExtrusionTranslateAnchor() const { + return impl().paint.template get<FillExtrusionTranslateAnchor>().value; } -void FillExtrusionLayer::setFillExtrusionTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) { - if (value == getFillExtrusionTranslateAnchor(klass)) +void FillExtrusionLayer::setFillExtrusionTranslateAnchor(PropertyValue<TranslateAnchorType> value) { + if (value == getFillExtrusionTranslateAnchor()) return; - impl->cascading.template get<FillExtrusionTranslateAnchor>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<FillExtrusionTranslateAnchor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void FillExtrusionLayer::setFillExtrusionTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<FillExtrusionTranslateAnchor>().setTransition(value, klass); +void FillExtrusionLayer::setFillExtrusionTranslateAnchorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<FillExtrusionTranslateAnchor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions FillExtrusionLayer::getFillExtrusionTranslateAnchorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<FillExtrusionTranslateAnchor>().getTransition(klass); +TransitionOptions FillExtrusionLayer::getFillExtrusionTranslateAnchorTransition() const { + return impl().paint.template get<FillExtrusionTranslateAnchor>().options; } PropertyValue<std::string> FillExtrusionLayer::getDefaultFillExtrusionPattern() { return { "" }; } -PropertyValue<std::string> FillExtrusionLayer::getFillExtrusionPattern(const optional<std::string>& klass) const { - return impl->cascading.template get<FillExtrusionPattern>().get(klass); +PropertyValue<std::string> FillExtrusionLayer::getFillExtrusionPattern() const { + return impl().paint.template get<FillExtrusionPattern>().value; } -void FillExtrusionLayer::setFillExtrusionPattern(PropertyValue<std::string> value, const optional<std::string>& klass) { - if (value == getFillExtrusionPattern(klass)) +void FillExtrusionLayer::setFillExtrusionPattern(PropertyValue<std::string> value) { + if (value == getFillExtrusionPattern()) return; - impl->cascading.template get<FillExtrusionPattern>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<FillExtrusionPattern>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void FillExtrusionLayer::setFillExtrusionPatternTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<FillExtrusionPattern>().setTransition(value, klass); +void FillExtrusionLayer::setFillExtrusionPatternTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<FillExtrusionPattern>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions FillExtrusionLayer::getFillExtrusionPatternTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<FillExtrusionPattern>().getTransition(klass); +TransitionOptions FillExtrusionLayer::getFillExtrusionPatternTransition() const { + return impl().paint.template get<FillExtrusionPattern>().options; } DataDrivenPropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionHeight() { return { 0 }; } -DataDrivenPropertyValue<float> FillExtrusionLayer::getFillExtrusionHeight(const optional<std::string>& klass) const { - return impl->cascading.template get<FillExtrusionHeight>().get(klass); +DataDrivenPropertyValue<float> FillExtrusionLayer::getFillExtrusionHeight() const { + return impl().paint.template get<FillExtrusionHeight>().value; } -void FillExtrusionLayer::setFillExtrusionHeight(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getFillExtrusionHeight(klass)) +void FillExtrusionLayer::setFillExtrusionHeight(DataDrivenPropertyValue<float> value) { + if (value == getFillExtrusionHeight()) return; - impl->cascading.template get<FillExtrusionHeight>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<FillExtrusionHeight>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void FillExtrusionLayer::setFillExtrusionHeightTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<FillExtrusionHeight>().setTransition(value, klass); +void FillExtrusionLayer::setFillExtrusionHeightTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<FillExtrusionHeight>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions FillExtrusionLayer::getFillExtrusionHeightTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<FillExtrusionHeight>().getTransition(klass); +TransitionOptions FillExtrusionLayer::getFillExtrusionHeightTransition() const { + return impl().paint.template get<FillExtrusionHeight>().options; } DataDrivenPropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionBase() { return { 0 }; } -DataDrivenPropertyValue<float> FillExtrusionLayer::getFillExtrusionBase(const optional<std::string>& klass) const { - return impl->cascading.template get<FillExtrusionBase>().get(klass); +DataDrivenPropertyValue<float> FillExtrusionLayer::getFillExtrusionBase() const { + return impl().paint.template get<FillExtrusionBase>().value; } -void FillExtrusionLayer::setFillExtrusionBase(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getFillExtrusionBase(klass)) +void FillExtrusionLayer::setFillExtrusionBase(DataDrivenPropertyValue<float> value) { + if (value == getFillExtrusionBase()) return; - impl->cascading.template get<FillExtrusionBase>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<FillExtrusionBase>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void FillExtrusionLayer::setFillExtrusionBaseTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<FillExtrusionBase>().setTransition(value, klass); +void FillExtrusionLayer::setFillExtrusionBaseTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<FillExtrusionBase>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions FillExtrusionLayer::getFillExtrusionBaseTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<FillExtrusionBase>().getTransition(klass); +TransitionOptions FillExtrusionLayer::getFillExtrusionBaseTransition() const { + return impl().paint.template get<FillExtrusionBase>().options; } } // namespace style diff --git a/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp b/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp index 5340541221..d37c2ad29b 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp @@ -1,11 +1,14 @@ #include <mbgl/style/layers/fill_extrusion_layer_impl.hpp> -#include <mbgl/renderer/render_fill_extrusion_layer.hpp> namespace mbgl { namespace style { -std::unique_ptr<RenderLayer> FillExtrusionLayer::Impl::createRenderLayer() const { - return std::make_unique<RenderFillExtrusionLayer>(*this); +bool FillExtrusionLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const { + assert(dynamic_cast<const FillExtrusionLayer::Impl*>(&other)); + const auto& impl = static_cast<const style::FillExtrusionLayer::Impl&>(other); + return filter != impl.filter || + visibility != impl.visibility || + paint.hasDataDrivenPropertyDifference(impl.paint); } } // namespace style diff --git a/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp index 2353bd99fe..9abc6fc4b3 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp +++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp @@ -9,13 +9,12 @@ namespace style { class FillExtrusionLayer::Impl : public Layer::Impl { public: - std::unique_ptr<Layer> clone() const override; - std::unique_ptr<Layer> cloneRef(const std::string& id) const override; - void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; + using Layer::Impl::Impl; - std::unique_ptr<RenderLayer> createRenderLayer() const override; + bool hasLayoutDifference(const Layer::Impl&) const override; + void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; - FillExtrusionPaintProperties::Cascading cascading; + FillExtrusionPaintProperties::Transitionable paint; }; } // namespace style diff --git a/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp b/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp index f41ce68b94..19be59a2fe 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp +++ b/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp @@ -5,6 +5,7 @@ #include <mbgl/style/types.hpp> #include <mbgl/style/layout_property.hpp> #include <mbgl/style/paint_property.hpp> +#include <mbgl/style/properties.hpp> #include <mbgl/programs/attributes.hpp> #include <mbgl/programs/uniforms.hpp> @@ -39,7 +40,7 @@ struct FillExtrusionBase : DataDrivenPaintProperty<float, attributes::a_base, un static float defaultValue() { return 0; } }; -class FillExtrusionPaintProperties : public PaintProperties< +class FillExtrusionPaintProperties : public Properties< FillExtrusionOpacity, FillExtrusionColor, FillExtrusionTranslate, diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp index 9fd9d33af3..65975752db 100644 --- a/src/mbgl/style/layers/fill_layer.cpp +++ b/src/mbgl/style/layers/fill_layer.cpp @@ -2,34 +2,34 @@ #include <mbgl/style/layers/fill_layer.hpp> #include <mbgl/style/layers/fill_layer_impl.hpp> -#include <mbgl/style/conversion/stringify.hpp> +#include <mbgl/style/layer_observer.hpp> namespace mbgl { namespace style { FillLayer::FillLayer(const std::string& layerID, const std::string& sourceID) - : Layer(LayerType::Fill, std::make_unique<Impl>()) - , impl(static_cast<Impl*>(baseImpl.get())) { - impl->id = layerID; - impl->source = sourceID; + : Layer(makeMutable<Impl>(LayerType::Fill, layerID, sourceID)) { } -FillLayer::FillLayer(const Impl& other) - : Layer(LayerType::Fill, std::make_unique<Impl>(other)) - , impl(static_cast<Impl*>(baseImpl.get())) { +FillLayer::FillLayer(Immutable<Impl> impl_) + : Layer(std::move(impl_)) { } FillLayer::~FillLayer() = default; -std::unique_ptr<Layer> FillLayer::Impl::clone() const { - return std::make_unique<FillLayer>(*this); +const FillLayer::Impl& FillLayer::impl() const { + return static_cast<const Impl&>(*baseImpl); } -std::unique_ptr<Layer> FillLayer::Impl::cloneRef(const std::string& id_) const { - auto result = std::make_unique<FillLayer>(*this); - result->impl->id = id_; - result->impl->cascading = FillPaintProperties::Cascading(); - return std::move(result); +Mutable<FillLayer::Impl> FillLayer::mutableImpl() const { + return makeMutable<Impl>(impl()); +} + +std::unique_ptr<Layer> FillLayer::cloneRef(const std::string& id_) const { + auto impl_ = mutableImpl(); + impl_->id = id_; + impl_->paint = FillPaintProperties::Transitionable(); + return std::make_unique<FillLayer>(std::move(impl_)); } void FillLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const { @@ -38,26 +38,55 @@ void FillLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer> // Source const std::string& FillLayer::getSourceID() const { - return impl->source; + return impl().source; } void FillLayer::setSourceLayer(const std::string& sourceLayer) { - impl->sourceLayer = sourceLayer; + auto impl_ = mutableImpl(); + impl_->sourceLayer = sourceLayer; + baseImpl = std::move(impl_); } const std::string& FillLayer::getSourceLayer() const { - return impl->sourceLayer; + return impl().sourceLayer; } // Filter void FillLayer::setFilter(const Filter& filter) { - impl->filter = filter; - impl->observer->onLayerFilterChanged(*this); + auto impl_ = mutableImpl(); + impl_->filter = filter; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } const Filter& FillLayer::getFilter() const { - return impl->filter; + return impl().filter; +} + +// Visibility + +void FillLayer::setVisibility(VisibilityType value) { + if (value == getVisibility()) + return; + auto impl_ = mutableImpl(); + impl_->visibility = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +// Zoom range + +void FillLayer::setMinZoom(float minZoom) { + auto impl_ = mutableImpl(); + impl_->minZoom = minZoom; + baseImpl = std::move(impl_); +} + +void FillLayer::setMaxZoom(float maxZoom) { + auto impl_ = mutableImpl(); + impl_->maxZoom = maxZoom; + baseImpl = std::move(impl_); } // Layout properties @@ -69,173 +98,189 @@ PropertyValue<bool> FillLayer::getDefaultFillAntialias() { return { true }; } -PropertyValue<bool> FillLayer::getFillAntialias(const optional<std::string>& klass) const { - return impl->cascading.template get<FillAntialias>().get(klass); +PropertyValue<bool> FillLayer::getFillAntialias() const { + return impl().paint.template get<FillAntialias>().value; } -void FillLayer::setFillAntialias(PropertyValue<bool> value, const optional<std::string>& klass) { - if (value == getFillAntialias(klass)) +void FillLayer::setFillAntialias(PropertyValue<bool> value) { + if (value == getFillAntialias()) return; - impl->cascading.template get<FillAntialias>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<FillAntialias>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void FillLayer::setFillAntialiasTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<FillAntialias>().setTransition(value, klass); +void FillLayer::setFillAntialiasTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<FillAntialias>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions FillLayer::getFillAntialiasTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<FillAntialias>().getTransition(klass); +TransitionOptions FillLayer::getFillAntialiasTransition() const { + return impl().paint.template get<FillAntialias>().options; } DataDrivenPropertyValue<float> FillLayer::getDefaultFillOpacity() { return { 1 }; } -DataDrivenPropertyValue<float> FillLayer::getFillOpacity(const optional<std::string>& klass) const { - return impl->cascading.template get<FillOpacity>().get(klass); +DataDrivenPropertyValue<float> FillLayer::getFillOpacity() const { + return impl().paint.template get<FillOpacity>().value; } -void FillLayer::setFillOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getFillOpacity(klass)) +void FillLayer::setFillOpacity(DataDrivenPropertyValue<float> value) { + if (value == getFillOpacity()) return; - impl->cascading.template get<FillOpacity>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<FillOpacity>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void FillLayer::setFillOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<FillOpacity>().setTransition(value, klass); +void FillLayer::setFillOpacityTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<FillOpacity>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions FillLayer::getFillOpacityTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<FillOpacity>().getTransition(klass); +TransitionOptions FillLayer::getFillOpacityTransition() const { + return impl().paint.template get<FillOpacity>().options; } DataDrivenPropertyValue<Color> FillLayer::getDefaultFillColor() { return { Color::black() }; } -DataDrivenPropertyValue<Color> FillLayer::getFillColor(const optional<std::string>& klass) const { - return impl->cascading.template get<FillColor>().get(klass); +DataDrivenPropertyValue<Color> FillLayer::getFillColor() const { + return impl().paint.template get<FillColor>().value; } -void FillLayer::setFillColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { - if (value == getFillColor(klass)) +void FillLayer::setFillColor(DataDrivenPropertyValue<Color> value) { + if (value == getFillColor()) return; - impl->cascading.template get<FillColor>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<FillColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void FillLayer::setFillColorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<FillColor>().setTransition(value, klass); +void FillLayer::setFillColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<FillColor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions FillLayer::getFillColorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<FillColor>().getTransition(klass); +TransitionOptions FillLayer::getFillColorTransition() const { + return impl().paint.template get<FillColor>().options; } DataDrivenPropertyValue<Color> FillLayer::getDefaultFillOutlineColor() { return { {} }; } -DataDrivenPropertyValue<Color> FillLayer::getFillOutlineColor(const optional<std::string>& klass) const { - return impl->cascading.template get<FillOutlineColor>().get(klass); +DataDrivenPropertyValue<Color> FillLayer::getFillOutlineColor() const { + return impl().paint.template get<FillOutlineColor>().value; } -void FillLayer::setFillOutlineColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { - if (value == getFillOutlineColor(klass)) +void FillLayer::setFillOutlineColor(DataDrivenPropertyValue<Color> value) { + if (value == getFillOutlineColor()) return; - impl->cascading.template get<FillOutlineColor>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<FillOutlineColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void FillLayer::setFillOutlineColorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<FillOutlineColor>().setTransition(value, klass); +void FillLayer::setFillOutlineColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<FillOutlineColor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions FillLayer::getFillOutlineColorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<FillOutlineColor>().getTransition(klass); +TransitionOptions FillLayer::getFillOutlineColorTransition() const { + return impl().paint.template get<FillOutlineColor>().options; } PropertyValue<std::array<float, 2>> FillLayer::getDefaultFillTranslate() { return { {{ 0, 0 }} }; } -PropertyValue<std::array<float, 2>> FillLayer::getFillTranslate(const optional<std::string>& klass) const { - return impl->cascading.template get<FillTranslate>().get(klass); +PropertyValue<std::array<float, 2>> FillLayer::getFillTranslate() const { + return impl().paint.template get<FillTranslate>().value; } -void FillLayer::setFillTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) { - if (value == getFillTranslate(klass)) +void FillLayer::setFillTranslate(PropertyValue<std::array<float, 2>> value) { + if (value == getFillTranslate()) return; - impl->cascading.template get<FillTranslate>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<FillTranslate>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void FillLayer::setFillTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<FillTranslate>().setTransition(value, klass); +void FillLayer::setFillTranslateTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<FillTranslate>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions FillLayer::getFillTranslateTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<FillTranslate>().getTransition(klass); +TransitionOptions FillLayer::getFillTranslateTransition() const { + return impl().paint.template get<FillTranslate>().options; } PropertyValue<TranslateAnchorType> FillLayer::getDefaultFillTranslateAnchor() { return { TranslateAnchorType::Map }; } -PropertyValue<TranslateAnchorType> FillLayer::getFillTranslateAnchor(const optional<std::string>& klass) const { - return impl->cascading.template get<FillTranslateAnchor>().get(klass); +PropertyValue<TranslateAnchorType> FillLayer::getFillTranslateAnchor() const { + return impl().paint.template get<FillTranslateAnchor>().value; } -void FillLayer::setFillTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) { - if (value == getFillTranslateAnchor(klass)) +void FillLayer::setFillTranslateAnchor(PropertyValue<TranslateAnchorType> value) { + if (value == getFillTranslateAnchor()) return; - impl->cascading.template get<FillTranslateAnchor>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<FillTranslateAnchor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void FillLayer::setFillTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<FillTranslateAnchor>().setTransition(value, klass); +void FillLayer::setFillTranslateAnchorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<FillTranslateAnchor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions FillLayer::getFillTranslateAnchorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<FillTranslateAnchor>().getTransition(klass); +TransitionOptions FillLayer::getFillTranslateAnchorTransition() const { + return impl().paint.template get<FillTranslateAnchor>().options; } PropertyValue<std::string> FillLayer::getDefaultFillPattern() { return { "" }; } -PropertyValue<std::string> FillLayer::getFillPattern(const optional<std::string>& klass) const { - return impl->cascading.template get<FillPattern>().get(klass); +PropertyValue<std::string> FillLayer::getFillPattern() const { + return impl().paint.template get<FillPattern>().value; } -void FillLayer::setFillPattern(PropertyValue<std::string> value, const optional<std::string>& klass) { - if (value == getFillPattern(klass)) +void FillLayer::setFillPattern(PropertyValue<std::string> value) { + if (value == getFillPattern()) return; - impl->cascading.template get<FillPattern>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<FillPattern>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void FillLayer::setFillPatternTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<FillPattern>().setTransition(value, klass); +void FillLayer::setFillPatternTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<FillPattern>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions FillLayer::getFillPatternTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<FillPattern>().getTransition(klass); +TransitionOptions FillLayer::getFillPatternTransition() const { + return impl().paint.template get<FillPattern>().options; } } // namespace style diff --git a/src/mbgl/style/layers/fill_layer_impl.cpp b/src/mbgl/style/layers/fill_layer_impl.cpp index 6ec55a58e3..0dc7ed14d5 100644 --- a/src/mbgl/style/layers/fill_layer_impl.cpp +++ b/src/mbgl/style/layers/fill_layer_impl.cpp @@ -1,11 +1,14 @@ #include <mbgl/style/layers/fill_layer_impl.hpp> -#include <mbgl/renderer/render_fill_layer.hpp> namespace mbgl { namespace style { -std::unique_ptr<RenderLayer> FillLayer::Impl::createRenderLayer() const { - return std::make_unique<RenderFillLayer>(*this); +bool FillLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const { + assert(dynamic_cast<const FillLayer::Impl*>(&other)); + const auto& impl = static_cast<const style::FillLayer::Impl&>(other); + return filter != impl.filter || + visibility != impl.visibility || + paint.hasDataDrivenPropertyDifference(impl.paint); } } // namespace style diff --git a/src/mbgl/style/layers/fill_layer_impl.hpp b/src/mbgl/style/layers/fill_layer_impl.hpp index 215558962e..2673cd7443 100644 --- a/src/mbgl/style/layers/fill_layer_impl.hpp +++ b/src/mbgl/style/layers/fill_layer_impl.hpp @@ -9,13 +9,12 @@ namespace style { class FillLayer::Impl : public Layer::Impl { public: - std::unique_ptr<Layer> clone() const override; - std::unique_ptr<Layer> cloneRef(const std::string& id) const override; - void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; + using Layer::Impl::Impl; - std::unique_ptr<RenderLayer> createRenderLayer() const override; + bool hasLayoutDifference(const Layer::Impl&) const override; + void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; - FillPaintProperties::Cascading cascading; + FillPaintProperties::Transitionable paint; }; } // namespace style diff --git a/src/mbgl/style/layers/fill_layer_properties.hpp b/src/mbgl/style/layers/fill_layer_properties.hpp index ee1e5158ce..cb01194515 100644 --- a/src/mbgl/style/layers/fill_layer_properties.hpp +++ b/src/mbgl/style/layers/fill_layer_properties.hpp @@ -5,6 +5,7 @@ #include <mbgl/style/types.hpp> #include <mbgl/style/layout_property.hpp> #include <mbgl/style/paint_property.hpp> +#include <mbgl/style/properties.hpp> #include <mbgl/programs/attributes.hpp> #include <mbgl/programs/uniforms.hpp> @@ -39,7 +40,7 @@ struct FillPattern : CrossFadedPaintProperty<std::string> { static std::string defaultValue() { return ""; } }; -class FillPaintProperties : public PaintProperties< +class FillPaintProperties : public Properties< FillAntialias, FillOpacity, FillColor, diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index 2f690c3158..573aabda8b 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -7,47 +7,45 @@ #include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp> #include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer_impl.hpp> -#include <mbgl/style/conversion/stringify.hpp> +#include <mbgl/style/layer_observer.hpp> namespace mbgl { namespace style { <% if (type === 'background') { -%> <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const std::string& layerID) - : Layer(LayerType::<%- camelize(type) %>, std::make_unique<Impl>()) - , impl(static_cast<Impl*>(baseImpl.get())) { - impl->id = layerID; + : Layer(makeMutable<Impl>(LayerType::<%- camelize(type) %>, layerID, std::string())) { } <% } else { -%> <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const std::string& layerID, const std::string& sourceID) - : Layer(LayerType::<%- camelize(type) %>, std::make_unique<Impl>()) - , impl(static_cast<Impl*>(baseImpl.get())) { - impl->id = layerID; - impl->source = sourceID; + : Layer(makeMutable<Impl>(LayerType::<%- camelize(type) %>, layerID, sourceID)) { } <% } -%> -<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const Impl& other) - : Layer(LayerType::<%- camelize(type) %>, std::make_unique<Impl>(other)) - , impl(static_cast<Impl*>(baseImpl.get())) { +<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(Immutable<Impl> impl_) + : Layer(std::move(impl_)) { } <%- camelize(type) %>Layer::~<%- camelize(type) %>Layer() = default; -std::unique_ptr<Layer> <%- camelize(type) %>Layer::Impl::clone() const { - return std::make_unique<<%- camelize(type) %>Layer>(*this); +const <%- camelize(type) %>Layer::Impl& <%- camelize(type) %>Layer::impl() const { + return static_cast<const Impl&>(*baseImpl); } -std::unique_ptr<Layer> <%- camelize(type) %>Layer::Impl::cloneRef(const std::string& id_) const { - auto result = std::make_unique<<%- camelize(type) %>Layer>(*this); - result->impl->id = id_; - result->impl->cascading = <%- camelize(type) %>PaintProperties::Cascading(); - return std::move(result); +Mutable<<%- camelize(type) %>Layer::Impl> <%- camelize(type) %>Layer::mutableImpl() const { + return makeMutable<Impl>(impl()); +} + +std::unique_ptr<Layer> <%- camelize(type) %>Layer::cloneRef(const std::string& id_) const { + auto impl_ = mutableImpl(); + impl_->id = id_; + impl_->paint = <%- camelize(type) %>PaintProperties::Transitionable(); + return std::make_unique<<%- camelize(type) %>Layer>(std::move(impl_)); } <% if (layoutProperties.length) { -%> void <%- camelize(type) %>Layer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>& writer) const { - conversion::stringify(writer, layout); + layout.stringify(writer); } <% } else { -%> void <%- camelize(type) %>Layer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const { @@ -58,31 +56,60 @@ void <%- camelize(type) %>Layer::Impl::stringifyLayout(rapidjson::Writer<rapidjs // Source const std::string& <%- camelize(type) %>Layer::getSourceID() const { - return impl->source; + return impl().source; } <% if (type !== 'raster') { -%> void <%- camelize(type) %>Layer::setSourceLayer(const std::string& sourceLayer) { - impl->sourceLayer = sourceLayer; + auto impl_ = mutableImpl(); + impl_->sourceLayer = sourceLayer; + baseImpl = std::move(impl_); } const std::string& <%- camelize(type) %>Layer::getSourceLayer() const { - return impl->sourceLayer; + return impl().sourceLayer; } // Filter void <%- camelize(type) %>Layer::setFilter(const Filter& filter) { - impl->filter = filter; - impl->observer->onLayerFilterChanged(*this); + auto impl_ = mutableImpl(); + impl_->filter = filter; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } const Filter& <%- camelize(type) %>Layer::getFilter() const { - return impl->filter; + return impl().filter; } <% } -%> <% } -%> +// Visibility + +void <%- camelize(type) %>Layer::setVisibility(VisibilityType value) { + if (value == getVisibility()) + return; + auto impl_ = mutableImpl(); + impl_->visibility = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +// Zoom range + +void <%- camelize(type) %>Layer::setMinZoom(float minZoom) { + auto impl_ = mutableImpl(); + impl_->minZoom = minZoom; + baseImpl = std::move(impl_); +} + +void <%- camelize(type) %>Layer::setMaxZoom(float maxZoom) { + auto impl_ = mutableImpl(); + impl_->maxZoom = maxZoom; + baseImpl = std::move(impl_); +} + // Layout properties <% for (const property of layoutProperties) { -%> @@ -91,14 +118,16 @@ const Filter& <%- camelize(type) %>Layer::getFilter() const { } <%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const { - return impl->layout.unevaluated.get<<%- camelize(property.name) %>>(); + return impl().layout.get<<%- camelize(property.name) %>>(); } void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> value) { if (value == get<%- camelize(property.name) %>()) return; - impl->layout.unevaluated.get<<%- camelize(property.name) %>>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "<%- property.name %>"); + auto impl_ = mutableImpl(); + impl_->layout.get<<%- camelize(property.name) %>>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } <% } -%> @@ -108,31 +137,27 @@ void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyV return { <%- defaultValue(property) %> }; } -<%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(const optional<std::string>& klass) const { - return impl->cascading.template get<<%- camelize(property.name) %>>().get(klass); +<%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const { + return impl().paint.template get<<%- camelize(property.name) %>>().value; } -void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> value, const optional<std::string>& klass) { - if (value == get<%- camelize(property.name) %>(klass)) +void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> value) { + if (value == get<%- camelize(property.name) %>()) return; - impl->cascading.template get<<%- camelize(property.name) %>>().set(value, klass); -<% if (isDataDriven(property)) { -%> - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } -<% } else { -%> - impl->observer->onLayerPaintPropertyChanged(*this); -<% } -%> + auto impl_ = mutableImpl(); + impl_->paint.template get<<%- camelize(property.name) %>>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>Transition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<<%- camelize(property.name) %>>().setTransition(value, klass); +void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>Transition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<<%- camelize(property.name) %>>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions <%- camelize(type) %>Layer::get<%- camelize(property.name) %>Transition(const optional<std::string>& klass) const { - return impl->cascading.template get<<%- camelize(property.name) %>>().getTransition(klass); +TransitionOptions <%- camelize(type) %>Layer::get<%- camelize(property.name) %>Transition() const { + return impl().paint.template get<<%- camelize(property.name) %>>().options; } <% } -%> diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs index 2a736ca388..cde1b80b7b 100644 --- a/src/mbgl/style/layers/layer_properties.hpp.ejs +++ b/src/mbgl/style/layers/layer_properties.hpp.ejs @@ -10,7 +10,9 @@ #include <mbgl/style/types.hpp> #include <mbgl/style/layout_property.hpp> #include <mbgl/style/paint_property.hpp> +#include <mbgl/style/properties.hpp> #include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> namespace mbgl { namespace style { @@ -29,7 +31,7 @@ struct <%- camelize(property.name) %> : <%- paintPropertyType(property, type) %> <% } -%> <% if (layoutProperties.length) { -%> -class <%- camelize(type) %>LayoutProperties : public LayoutProperties< +class <%- camelize(type) %>LayoutProperties : public Properties< <% for (const property of layoutProperties.slice(0, -1)) { -%> <%- camelize(property.name) %>, <% } -%> @@ -37,7 +39,7 @@ class <%- camelize(type) %>LayoutProperties : public LayoutProperties< > {}; <% } -%> -class <%- camelize(type) %>PaintProperties : public PaintProperties< +class <%- camelize(type) %>PaintProperties : public Properties< <% for (const property of paintProperties.slice(0, -1)) { -%> <%- camelize(property.name) %>, <% } -%> diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index 7f1575aad5..1c7f0d28ee 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -2,63 +2,92 @@ #include <mbgl/style/layers/line_layer.hpp> #include <mbgl/style/layers/line_layer_impl.hpp> -#include <mbgl/style/conversion/stringify.hpp> +#include <mbgl/style/layer_observer.hpp> namespace mbgl { namespace style { LineLayer::LineLayer(const std::string& layerID, const std::string& sourceID) - : Layer(LayerType::Line, std::make_unique<Impl>()) - , impl(static_cast<Impl*>(baseImpl.get())) { - impl->id = layerID; - impl->source = sourceID; + : Layer(makeMutable<Impl>(LayerType::Line, layerID, sourceID)) { } -LineLayer::LineLayer(const Impl& other) - : Layer(LayerType::Line, std::make_unique<Impl>(other)) - , impl(static_cast<Impl*>(baseImpl.get())) { +LineLayer::LineLayer(Immutable<Impl> impl_) + : Layer(std::move(impl_)) { } LineLayer::~LineLayer() = default; -std::unique_ptr<Layer> LineLayer::Impl::clone() const { - return std::make_unique<LineLayer>(*this); +const LineLayer::Impl& LineLayer::impl() const { + return static_cast<const Impl&>(*baseImpl); } -std::unique_ptr<Layer> LineLayer::Impl::cloneRef(const std::string& id_) const { - auto result = std::make_unique<LineLayer>(*this); - result->impl->id = id_; - result->impl->cascading = LinePaintProperties::Cascading(); - return std::move(result); +Mutable<LineLayer::Impl> LineLayer::mutableImpl() const { + return makeMutable<Impl>(impl()); +} + +std::unique_ptr<Layer> LineLayer::cloneRef(const std::string& id_) const { + auto impl_ = mutableImpl(); + impl_->id = id_; + impl_->paint = LinePaintProperties::Transitionable(); + return std::make_unique<LineLayer>(std::move(impl_)); } void LineLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>& writer) const { - conversion::stringify(writer, layout); + layout.stringify(writer); } // Source const std::string& LineLayer::getSourceID() const { - return impl->source; + return impl().source; } void LineLayer::setSourceLayer(const std::string& sourceLayer) { - impl->sourceLayer = sourceLayer; + auto impl_ = mutableImpl(); + impl_->sourceLayer = sourceLayer; + baseImpl = std::move(impl_); } const std::string& LineLayer::getSourceLayer() const { - return impl->sourceLayer; + return impl().sourceLayer; } // Filter void LineLayer::setFilter(const Filter& filter) { - impl->filter = filter; - impl->observer->onLayerFilterChanged(*this); + auto impl_ = mutableImpl(); + impl_->filter = filter; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } const Filter& LineLayer::getFilter() const { - return impl->filter; + return impl().filter; +} + +// Visibility + +void LineLayer::setVisibility(VisibilityType value) { + if (value == getVisibility()) + return; + auto impl_ = mutableImpl(); + impl_->visibility = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +// Zoom range + +void LineLayer::setMinZoom(float minZoom) { + auto impl_ = mutableImpl(); + impl_->minZoom = minZoom; + baseImpl = std::move(impl_); +} + +void LineLayer::setMaxZoom(float maxZoom) { + auto impl_ = mutableImpl(); + impl_->maxZoom = maxZoom; + baseImpl = std::move(impl_); } // Layout properties @@ -68,56 +97,64 @@ PropertyValue<LineCapType> LineLayer::getDefaultLineCap() { } PropertyValue<LineCapType> LineLayer::getLineCap() const { - return impl->layout.unevaluated.get<LineCap>(); + return impl().layout.get<LineCap>(); } void LineLayer::setLineCap(PropertyValue<LineCapType> value) { if (value == getLineCap()) return; - impl->layout.unevaluated.get<LineCap>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "line-cap"); + auto impl_ = mutableImpl(); + impl_->layout.get<LineCap>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -PropertyValue<LineJoinType> LineLayer::getDefaultLineJoin() { +DataDrivenPropertyValue<LineJoinType> LineLayer::getDefaultLineJoin() { return LineJoin::defaultValue(); } -PropertyValue<LineJoinType> LineLayer::getLineJoin() const { - return impl->layout.unevaluated.get<LineJoin>(); +DataDrivenPropertyValue<LineJoinType> LineLayer::getLineJoin() const { + return impl().layout.get<LineJoin>(); } -void LineLayer::setLineJoin(PropertyValue<LineJoinType> value) { +void LineLayer::setLineJoin(DataDrivenPropertyValue<LineJoinType> value) { if (value == getLineJoin()) return; - impl->layout.unevaluated.get<LineJoin>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "line-join"); + auto impl_ = mutableImpl(); + impl_->layout.get<LineJoin>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<float> LineLayer::getDefaultLineMiterLimit() { return LineMiterLimit::defaultValue(); } PropertyValue<float> LineLayer::getLineMiterLimit() const { - return impl->layout.unevaluated.get<LineMiterLimit>(); + return impl().layout.get<LineMiterLimit>(); } void LineLayer::setLineMiterLimit(PropertyValue<float> value) { if (value == getLineMiterLimit()) return; - impl->layout.unevaluated.get<LineMiterLimit>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "line-miter-limit"); + auto impl_ = mutableImpl(); + impl_->layout.get<LineMiterLimit>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<float> LineLayer::getDefaultLineRoundLimit() { return LineRoundLimit::defaultValue(); } PropertyValue<float> LineLayer::getLineRoundLimit() const { - return impl->layout.unevaluated.get<LineRoundLimit>(); + return impl().layout.get<LineRoundLimit>(); } void LineLayer::setLineRoundLimit(PropertyValue<float> value) { if (value == getLineRoundLimit()) return; - impl->layout.unevaluated.get<LineRoundLimit>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "line-round-limit"); + auto impl_ = mutableImpl(); + impl_->layout.get<LineRoundLimit>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } // Paint properties @@ -126,250 +163,270 @@ DataDrivenPropertyValue<float> LineLayer::getDefaultLineOpacity() { return { 1 }; } -DataDrivenPropertyValue<float> LineLayer::getLineOpacity(const optional<std::string>& klass) const { - return impl->cascading.template get<LineOpacity>().get(klass); +DataDrivenPropertyValue<float> LineLayer::getLineOpacity() const { + return impl().paint.template get<LineOpacity>().value; } -void LineLayer::setLineOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getLineOpacity(klass)) +void LineLayer::setLineOpacity(DataDrivenPropertyValue<float> value) { + if (value == getLineOpacity()) return; - impl->cascading.template get<LineOpacity>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<LineOpacity>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void LineLayer::setLineOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<LineOpacity>().setTransition(value, klass); +void LineLayer::setLineOpacityTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<LineOpacity>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions LineLayer::getLineOpacityTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<LineOpacity>().getTransition(klass); +TransitionOptions LineLayer::getLineOpacityTransition() const { + return impl().paint.template get<LineOpacity>().options; } DataDrivenPropertyValue<Color> LineLayer::getDefaultLineColor() { return { Color::black() }; } -DataDrivenPropertyValue<Color> LineLayer::getLineColor(const optional<std::string>& klass) const { - return impl->cascading.template get<LineColor>().get(klass); +DataDrivenPropertyValue<Color> LineLayer::getLineColor() const { + return impl().paint.template get<LineColor>().value; } -void LineLayer::setLineColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { - if (value == getLineColor(klass)) +void LineLayer::setLineColor(DataDrivenPropertyValue<Color> value) { + if (value == getLineColor()) return; - impl->cascading.template get<LineColor>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<LineColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void LineLayer::setLineColorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<LineColor>().setTransition(value, klass); +void LineLayer::setLineColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<LineColor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions LineLayer::getLineColorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<LineColor>().getTransition(klass); +TransitionOptions LineLayer::getLineColorTransition() const { + return impl().paint.template get<LineColor>().options; } PropertyValue<std::array<float, 2>> LineLayer::getDefaultLineTranslate() { return { {{ 0, 0 }} }; } -PropertyValue<std::array<float, 2>> LineLayer::getLineTranslate(const optional<std::string>& klass) const { - return impl->cascading.template get<LineTranslate>().get(klass); +PropertyValue<std::array<float, 2>> LineLayer::getLineTranslate() const { + return impl().paint.template get<LineTranslate>().value; } -void LineLayer::setLineTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) { - if (value == getLineTranslate(klass)) +void LineLayer::setLineTranslate(PropertyValue<std::array<float, 2>> value) { + if (value == getLineTranslate()) return; - impl->cascading.template get<LineTranslate>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<LineTranslate>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void LineLayer::setLineTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<LineTranslate>().setTransition(value, klass); +void LineLayer::setLineTranslateTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<LineTranslate>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions LineLayer::getLineTranslateTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<LineTranslate>().getTransition(klass); +TransitionOptions LineLayer::getLineTranslateTransition() const { + return impl().paint.template get<LineTranslate>().options; } PropertyValue<TranslateAnchorType> LineLayer::getDefaultLineTranslateAnchor() { return { TranslateAnchorType::Map }; } -PropertyValue<TranslateAnchorType> LineLayer::getLineTranslateAnchor(const optional<std::string>& klass) const { - return impl->cascading.template get<LineTranslateAnchor>().get(klass); +PropertyValue<TranslateAnchorType> LineLayer::getLineTranslateAnchor() const { + return impl().paint.template get<LineTranslateAnchor>().value; } -void LineLayer::setLineTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) { - if (value == getLineTranslateAnchor(klass)) +void LineLayer::setLineTranslateAnchor(PropertyValue<TranslateAnchorType> value) { + if (value == getLineTranslateAnchor()) return; - impl->cascading.template get<LineTranslateAnchor>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<LineTranslateAnchor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void LineLayer::setLineTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<LineTranslateAnchor>().setTransition(value, klass); +void LineLayer::setLineTranslateAnchorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<LineTranslateAnchor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions LineLayer::getLineTranslateAnchorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<LineTranslateAnchor>().getTransition(klass); +TransitionOptions LineLayer::getLineTranslateAnchorTransition() const { + return impl().paint.template get<LineTranslateAnchor>().options; } -PropertyValue<float> LineLayer::getDefaultLineWidth() { +DataDrivenPropertyValue<float> LineLayer::getDefaultLineWidth() { return { 1 }; } -PropertyValue<float> LineLayer::getLineWidth(const optional<std::string>& klass) const { - return impl->cascading.template get<LineWidth>().get(klass); +DataDrivenPropertyValue<float> LineLayer::getLineWidth() const { + return impl().paint.template get<LineWidth>().value; } -void LineLayer::setLineWidth(PropertyValue<float> value, const optional<std::string>& klass) { - if (value == getLineWidth(klass)) +void LineLayer::setLineWidth(DataDrivenPropertyValue<float> value) { + if (value == getLineWidth()) return; - impl->cascading.template get<LineWidth>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<LineWidth>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void LineLayer::setLineWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<LineWidth>().setTransition(value, klass); +void LineLayer::setLineWidthTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<LineWidth>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions LineLayer::getLineWidthTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<LineWidth>().getTransition(klass); +TransitionOptions LineLayer::getLineWidthTransition() const { + return impl().paint.template get<LineWidth>().options; } DataDrivenPropertyValue<float> LineLayer::getDefaultLineGapWidth() { return { 0 }; } -DataDrivenPropertyValue<float> LineLayer::getLineGapWidth(const optional<std::string>& klass) const { - return impl->cascading.template get<LineGapWidth>().get(klass); +DataDrivenPropertyValue<float> LineLayer::getLineGapWidth() const { + return impl().paint.template get<LineGapWidth>().value; } -void LineLayer::setLineGapWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getLineGapWidth(klass)) +void LineLayer::setLineGapWidth(DataDrivenPropertyValue<float> value) { + if (value == getLineGapWidth()) return; - impl->cascading.template get<LineGapWidth>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<LineGapWidth>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void LineLayer::setLineGapWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<LineGapWidth>().setTransition(value, klass); +void LineLayer::setLineGapWidthTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<LineGapWidth>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions LineLayer::getLineGapWidthTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<LineGapWidth>().getTransition(klass); +TransitionOptions LineLayer::getLineGapWidthTransition() const { + return impl().paint.template get<LineGapWidth>().options; } DataDrivenPropertyValue<float> LineLayer::getDefaultLineOffset() { return { 0 }; } -DataDrivenPropertyValue<float> LineLayer::getLineOffset(const optional<std::string>& klass) const { - return impl->cascading.template get<LineOffset>().get(klass); +DataDrivenPropertyValue<float> LineLayer::getLineOffset() const { + return impl().paint.template get<LineOffset>().value; } -void LineLayer::setLineOffset(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getLineOffset(klass)) +void LineLayer::setLineOffset(DataDrivenPropertyValue<float> value) { + if (value == getLineOffset()) return; - impl->cascading.template get<LineOffset>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<LineOffset>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void LineLayer::setLineOffsetTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<LineOffset>().setTransition(value, klass); +void LineLayer::setLineOffsetTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<LineOffset>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions LineLayer::getLineOffsetTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<LineOffset>().getTransition(klass); +TransitionOptions LineLayer::getLineOffsetTransition() const { + return impl().paint.template get<LineOffset>().options; } DataDrivenPropertyValue<float> LineLayer::getDefaultLineBlur() { return { 0 }; } -DataDrivenPropertyValue<float> LineLayer::getLineBlur(const optional<std::string>& klass) const { - return impl->cascading.template get<LineBlur>().get(klass); +DataDrivenPropertyValue<float> LineLayer::getLineBlur() const { + return impl().paint.template get<LineBlur>().value; } -void LineLayer::setLineBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getLineBlur(klass)) +void LineLayer::setLineBlur(DataDrivenPropertyValue<float> value) { + if (value == getLineBlur()) return; - impl->cascading.template get<LineBlur>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<LineBlur>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void LineLayer::setLineBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<LineBlur>().setTransition(value, klass); +void LineLayer::setLineBlurTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<LineBlur>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions LineLayer::getLineBlurTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<LineBlur>().getTransition(klass); +TransitionOptions LineLayer::getLineBlurTransition() const { + return impl().paint.template get<LineBlur>().options; } PropertyValue<std::vector<float>> LineLayer::getDefaultLineDasharray() { return { { } }; } -PropertyValue<std::vector<float>> LineLayer::getLineDasharray(const optional<std::string>& klass) const { - return impl->cascading.template get<LineDasharray>().get(klass); +PropertyValue<std::vector<float>> LineLayer::getLineDasharray() const { + return impl().paint.template get<LineDasharray>().value; } -void LineLayer::setLineDasharray(PropertyValue<std::vector<float>> value, const optional<std::string>& klass) { - if (value == getLineDasharray(klass)) +void LineLayer::setLineDasharray(PropertyValue<std::vector<float>> value) { + if (value == getLineDasharray()) return; - impl->cascading.template get<LineDasharray>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<LineDasharray>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void LineLayer::setLineDasharrayTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<LineDasharray>().setTransition(value, klass); +void LineLayer::setLineDasharrayTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<LineDasharray>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions LineLayer::getLineDasharrayTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<LineDasharray>().getTransition(klass); +TransitionOptions LineLayer::getLineDasharrayTransition() const { + return impl().paint.template get<LineDasharray>().options; } PropertyValue<std::string> LineLayer::getDefaultLinePattern() { return { "" }; } -PropertyValue<std::string> LineLayer::getLinePattern(const optional<std::string>& klass) const { - return impl->cascading.template get<LinePattern>().get(klass); +PropertyValue<std::string> LineLayer::getLinePattern() const { + return impl().paint.template get<LinePattern>().value; } -void LineLayer::setLinePattern(PropertyValue<std::string> value, const optional<std::string>& klass) { - if (value == getLinePattern(klass)) +void LineLayer::setLinePattern(PropertyValue<std::string> value) { + if (value == getLinePattern()) return; - impl->cascading.template get<LinePattern>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<LinePattern>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void LineLayer::setLinePatternTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<LinePattern>().setTransition(value, klass); +void LineLayer::setLinePatternTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<LinePattern>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions LineLayer::getLinePatternTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<LinePattern>().getTransition(klass); +TransitionOptions LineLayer::getLinePatternTransition() const { + return impl().paint.template get<LinePattern>().options; } } // namespace style diff --git a/src/mbgl/style/layers/line_layer_impl.cpp b/src/mbgl/style/layers/line_layer_impl.cpp index 973a77abf4..bee88d6a47 100644 --- a/src/mbgl/style/layers/line_layer_impl.cpp +++ b/src/mbgl/style/layers/line_layer_impl.cpp @@ -1,11 +1,15 @@ #include <mbgl/style/layers/line_layer_impl.hpp> -#include <mbgl/renderer/render_line_layer.hpp> namespace mbgl { namespace style { -std::unique_ptr<RenderLayer> LineLayer::Impl::createRenderLayer() const { - return std::make_unique<RenderLineLayer>(*this); +bool LineLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const { + assert(dynamic_cast<const LineLayer::Impl*>(&other)); + const auto& impl = static_cast<const style::LineLayer::Impl&>(other); + return filter != impl.filter || + visibility != impl.visibility || + layout != impl.layout || + paint.hasDataDrivenPropertyDifference(impl.paint); } } // namespace style diff --git a/src/mbgl/style/layers/line_layer_impl.hpp b/src/mbgl/style/layers/line_layer_impl.hpp index 02c9c85f00..04adc0e85c 100644 --- a/src/mbgl/style/layers/line_layer_impl.hpp +++ b/src/mbgl/style/layers/line_layer_impl.hpp @@ -9,14 +9,13 @@ namespace style { class LineLayer::Impl : public Layer::Impl { public: - std::unique_ptr<Layer> clone() const override; - std::unique_ptr<Layer> cloneRef(const std::string& id) const override; - void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; + using Layer::Impl::Impl; - std::unique_ptr<RenderLayer> createRenderLayer() const override; + bool hasLayoutDifference(const Layer::Impl&) const override; + void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; - LineLayoutProperties layout; - LinePaintProperties::Cascading cascading; + LineLayoutProperties::Unevaluated layout; + LinePaintProperties::Transitionable paint; }; } // namespace style diff --git a/src/mbgl/style/layers/line_layer_properties.hpp b/src/mbgl/style/layers/line_layer_properties.hpp index 6c301e6a0e..aeaf51698a 100644 --- a/src/mbgl/style/layers/line_layer_properties.hpp +++ b/src/mbgl/style/layers/line_layer_properties.hpp @@ -5,6 +5,7 @@ #include <mbgl/style/types.hpp> #include <mbgl/style/layout_property.hpp> #include <mbgl/style/paint_property.hpp> +#include <mbgl/style/properties.hpp> #include <mbgl/programs/attributes.hpp> #include <mbgl/programs/uniforms.hpp> @@ -16,7 +17,7 @@ struct LineCap : LayoutProperty<LineCapType> { static LineCapType defaultValue() { return LineCapType::Butt; } }; -struct LineJoin : LayoutProperty<LineJoinType> { +struct LineJoin : DataDrivenLayoutProperty<LineJoinType> { static constexpr const char * key = "line-join"; static LineJoinType defaultValue() { return LineJoinType::Miter; } }; @@ -47,7 +48,7 @@ struct LineTranslateAnchor : PaintProperty<TranslateAnchorType> { static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; } }; -struct LineWidth : PaintProperty<float> { +struct LineWidth : DataDrivenPaintProperty<float, attributes::a_width, uniforms::u_width> { static float defaultValue() { return 1; } }; @@ -71,14 +72,14 @@ struct LinePattern : CrossFadedPaintProperty<std::string> { static std::string defaultValue() { return ""; } }; -class LineLayoutProperties : public LayoutProperties< +class LineLayoutProperties : public Properties< LineCap, LineJoin, LineMiterLimit, LineRoundLimit > {}; -class LinePaintProperties : public PaintProperties< +class LinePaintProperties : public Properties< LineOpacity, LineColor, LineTranslate, diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp index b525f9eaa4..a9a8d273fa 100644 --- a/src/mbgl/style/layers/raster_layer.cpp +++ b/src/mbgl/style/layers/raster_layer.cpp @@ -2,34 +2,34 @@ #include <mbgl/style/layers/raster_layer.hpp> #include <mbgl/style/layers/raster_layer_impl.hpp> -#include <mbgl/style/conversion/stringify.hpp> +#include <mbgl/style/layer_observer.hpp> namespace mbgl { namespace style { RasterLayer::RasterLayer(const std::string& layerID, const std::string& sourceID) - : Layer(LayerType::Raster, std::make_unique<Impl>()) - , impl(static_cast<Impl*>(baseImpl.get())) { - impl->id = layerID; - impl->source = sourceID; + : Layer(makeMutable<Impl>(LayerType::Raster, layerID, sourceID)) { } -RasterLayer::RasterLayer(const Impl& other) - : Layer(LayerType::Raster, std::make_unique<Impl>(other)) - , impl(static_cast<Impl*>(baseImpl.get())) { +RasterLayer::RasterLayer(Immutable<Impl> impl_) + : Layer(std::move(impl_)) { } RasterLayer::~RasterLayer() = default; -std::unique_ptr<Layer> RasterLayer::Impl::clone() const { - return std::make_unique<RasterLayer>(*this); +const RasterLayer::Impl& RasterLayer::impl() const { + return static_cast<const Impl&>(*baseImpl); } -std::unique_ptr<Layer> RasterLayer::Impl::cloneRef(const std::string& id_) const { - auto result = std::make_unique<RasterLayer>(*this); - result->impl->id = id_; - result->impl->cascading = RasterPaintProperties::Cascading(); - return std::move(result); +Mutable<RasterLayer::Impl> RasterLayer::mutableImpl() const { + return makeMutable<Impl>(impl()); +} + +std::unique_ptr<Layer> RasterLayer::cloneRef(const std::string& id_) const { + auto impl_ = mutableImpl(); + impl_->id = id_; + impl_->paint = RasterPaintProperties::Transitionable(); + return std::make_unique<RasterLayer>(std::move(impl_)); } void RasterLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const { @@ -38,10 +38,35 @@ void RasterLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffe // Source const std::string& RasterLayer::getSourceID() const { - return impl->source; + return impl().source; } +// Visibility + +void RasterLayer::setVisibility(VisibilityType value) { + if (value == getVisibility()) + return; + auto impl_ = mutableImpl(); + impl_->visibility = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +// Zoom range + +void RasterLayer::setMinZoom(float minZoom) { + auto impl_ = mutableImpl(); + impl_->minZoom = minZoom; + baseImpl = std::move(impl_); +} + +void RasterLayer::setMaxZoom(float maxZoom) { + auto impl_ = mutableImpl(); + impl_->maxZoom = maxZoom; + baseImpl = std::move(impl_); +} + // Layout properties @@ -51,161 +76,189 @@ PropertyValue<float> RasterLayer::getDefaultRasterOpacity() { return { 1 }; } -PropertyValue<float> RasterLayer::getRasterOpacity(const optional<std::string>& klass) const { - return impl->cascading.template get<RasterOpacity>().get(klass); +PropertyValue<float> RasterLayer::getRasterOpacity() const { + return impl().paint.template get<RasterOpacity>().value; } -void RasterLayer::setRasterOpacity(PropertyValue<float> value, const optional<std::string>& klass) { - if (value == getRasterOpacity(klass)) +void RasterLayer::setRasterOpacity(PropertyValue<float> value) { + if (value == getRasterOpacity()) return; - impl->cascading.template get<RasterOpacity>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterOpacity>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void RasterLayer::setRasterOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<RasterOpacity>().setTransition(value, klass); +void RasterLayer::setRasterOpacityTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterOpacity>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions RasterLayer::getRasterOpacityTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<RasterOpacity>().getTransition(klass); +TransitionOptions RasterLayer::getRasterOpacityTransition() const { + return impl().paint.template get<RasterOpacity>().options; } PropertyValue<float> RasterLayer::getDefaultRasterHueRotate() { return { 0 }; } -PropertyValue<float> RasterLayer::getRasterHueRotate(const optional<std::string>& klass) const { - return impl->cascading.template get<RasterHueRotate>().get(klass); +PropertyValue<float> RasterLayer::getRasterHueRotate() const { + return impl().paint.template get<RasterHueRotate>().value; } -void RasterLayer::setRasterHueRotate(PropertyValue<float> value, const optional<std::string>& klass) { - if (value == getRasterHueRotate(klass)) +void RasterLayer::setRasterHueRotate(PropertyValue<float> value) { + if (value == getRasterHueRotate()) return; - impl->cascading.template get<RasterHueRotate>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterHueRotate>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void RasterLayer::setRasterHueRotateTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<RasterHueRotate>().setTransition(value, klass); +void RasterLayer::setRasterHueRotateTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterHueRotate>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions RasterLayer::getRasterHueRotateTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<RasterHueRotate>().getTransition(klass); +TransitionOptions RasterLayer::getRasterHueRotateTransition() const { + return impl().paint.template get<RasterHueRotate>().options; } PropertyValue<float> RasterLayer::getDefaultRasterBrightnessMin() { return { 0 }; } -PropertyValue<float> RasterLayer::getRasterBrightnessMin(const optional<std::string>& klass) const { - return impl->cascading.template get<RasterBrightnessMin>().get(klass); +PropertyValue<float> RasterLayer::getRasterBrightnessMin() const { + return impl().paint.template get<RasterBrightnessMin>().value; } -void RasterLayer::setRasterBrightnessMin(PropertyValue<float> value, const optional<std::string>& klass) { - if (value == getRasterBrightnessMin(klass)) +void RasterLayer::setRasterBrightnessMin(PropertyValue<float> value) { + if (value == getRasterBrightnessMin()) return; - impl->cascading.template get<RasterBrightnessMin>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterBrightnessMin>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void RasterLayer::setRasterBrightnessMinTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<RasterBrightnessMin>().setTransition(value, klass); +void RasterLayer::setRasterBrightnessMinTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterBrightnessMin>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions RasterLayer::getRasterBrightnessMinTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<RasterBrightnessMin>().getTransition(klass); +TransitionOptions RasterLayer::getRasterBrightnessMinTransition() const { + return impl().paint.template get<RasterBrightnessMin>().options; } PropertyValue<float> RasterLayer::getDefaultRasterBrightnessMax() { return { 1 }; } -PropertyValue<float> RasterLayer::getRasterBrightnessMax(const optional<std::string>& klass) const { - return impl->cascading.template get<RasterBrightnessMax>().get(klass); +PropertyValue<float> RasterLayer::getRasterBrightnessMax() const { + return impl().paint.template get<RasterBrightnessMax>().value; } -void RasterLayer::setRasterBrightnessMax(PropertyValue<float> value, const optional<std::string>& klass) { - if (value == getRasterBrightnessMax(klass)) +void RasterLayer::setRasterBrightnessMax(PropertyValue<float> value) { + if (value == getRasterBrightnessMax()) return; - impl->cascading.template get<RasterBrightnessMax>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterBrightnessMax>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void RasterLayer::setRasterBrightnessMaxTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<RasterBrightnessMax>().setTransition(value, klass); +void RasterLayer::setRasterBrightnessMaxTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterBrightnessMax>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions RasterLayer::getRasterBrightnessMaxTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<RasterBrightnessMax>().getTransition(klass); +TransitionOptions RasterLayer::getRasterBrightnessMaxTransition() const { + return impl().paint.template get<RasterBrightnessMax>().options; } PropertyValue<float> RasterLayer::getDefaultRasterSaturation() { return { 0 }; } -PropertyValue<float> RasterLayer::getRasterSaturation(const optional<std::string>& klass) const { - return impl->cascading.template get<RasterSaturation>().get(klass); +PropertyValue<float> RasterLayer::getRasterSaturation() const { + return impl().paint.template get<RasterSaturation>().value; } -void RasterLayer::setRasterSaturation(PropertyValue<float> value, const optional<std::string>& klass) { - if (value == getRasterSaturation(klass)) +void RasterLayer::setRasterSaturation(PropertyValue<float> value) { + if (value == getRasterSaturation()) return; - impl->cascading.template get<RasterSaturation>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterSaturation>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void RasterLayer::setRasterSaturationTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<RasterSaturation>().setTransition(value, klass); +void RasterLayer::setRasterSaturationTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterSaturation>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions RasterLayer::getRasterSaturationTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<RasterSaturation>().getTransition(klass); +TransitionOptions RasterLayer::getRasterSaturationTransition() const { + return impl().paint.template get<RasterSaturation>().options; } PropertyValue<float> RasterLayer::getDefaultRasterContrast() { return { 0 }; } -PropertyValue<float> RasterLayer::getRasterContrast(const optional<std::string>& klass) const { - return impl->cascading.template get<RasterContrast>().get(klass); +PropertyValue<float> RasterLayer::getRasterContrast() const { + return impl().paint.template get<RasterContrast>().value; } -void RasterLayer::setRasterContrast(PropertyValue<float> value, const optional<std::string>& klass) { - if (value == getRasterContrast(klass)) +void RasterLayer::setRasterContrast(PropertyValue<float> value) { + if (value == getRasterContrast()) return; - impl->cascading.template get<RasterContrast>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterContrast>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void RasterLayer::setRasterContrastTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<RasterContrast>().setTransition(value, klass); +void RasterLayer::setRasterContrastTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterContrast>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions RasterLayer::getRasterContrastTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<RasterContrast>().getTransition(klass); +TransitionOptions RasterLayer::getRasterContrastTransition() const { + return impl().paint.template get<RasterContrast>().options; } PropertyValue<float> RasterLayer::getDefaultRasterFadeDuration() { return { 300 }; } -PropertyValue<float> RasterLayer::getRasterFadeDuration(const optional<std::string>& klass) const { - return impl->cascading.template get<RasterFadeDuration>().get(klass); +PropertyValue<float> RasterLayer::getRasterFadeDuration() const { + return impl().paint.template get<RasterFadeDuration>().value; } -void RasterLayer::setRasterFadeDuration(PropertyValue<float> value, const optional<std::string>& klass) { - if (value == getRasterFadeDuration(klass)) +void RasterLayer::setRasterFadeDuration(PropertyValue<float> value) { + if (value == getRasterFadeDuration()) return; - impl->cascading.template get<RasterFadeDuration>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterFadeDuration>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void RasterLayer::setRasterFadeDurationTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<RasterFadeDuration>().setTransition(value, klass); +void RasterLayer::setRasterFadeDurationTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterFadeDuration>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions RasterLayer::getRasterFadeDurationTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<RasterFadeDuration>().getTransition(klass); +TransitionOptions RasterLayer::getRasterFadeDurationTransition() const { + return impl().paint.template get<RasterFadeDuration>().options; } } // namespace style diff --git a/src/mbgl/style/layers/raster_layer_impl.cpp b/src/mbgl/style/layers/raster_layer_impl.cpp index fa9f80dac6..a995f50dd3 100644 --- a/src/mbgl/style/layers/raster_layer_impl.cpp +++ b/src/mbgl/style/layers/raster_layer_impl.cpp @@ -1,11 +1,10 @@ #include <mbgl/style/layers/raster_layer_impl.hpp> -#include <mbgl/renderer/render_raster_layer.hpp> namespace mbgl { namespace style { -std::unique_ptr<RenderLayer> RasterLayer::Impl::createRenderLayer() const { - return std::make_unique<RenderRasterLayer>(*this); +bool RasterLayer::Impl::hasLayoutDifference(const Layer::Impl&) const { + return false; } } // namespace style diff --git a/src/mbgl/style/layers/raster_layer_impl.hpp b/src/mbgl/style/layers/raster_layer_impl.hpp index edf5f9111b..adbe703e92 100644 --- a/src/mbgl/style/layers/raster_layer_impl.hpp +++ b/src/mbgl/style/layers/raster_layer_impl.hpp @@ -9,13 +9,12 @@ namespace style { class RasterLayer::Impl : public Layer::Impl { public: - std::unique_ptr<Layer> clone() const override; - std::unique_ptr<Layer> cloneRef(const std::string& id) const override; - void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; + using Layer::Impl::Impl; - std::unique_ptr<RenderLayer> createRenderLayer() const override; + bool hasLayoutDifference(const Layer::Impl&) const override; + void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; - RasterPaintProperties::Cascading cascading; + RasterPaintProperties::Transitionable paint; }; } // namespace style diff --git a/src/mbgl/style/layers/raster_layer_properties.hpp b/src/mbgl/style/layers/raster_layer_properties.hpp index 219fe34d8c..12df09f32c 100644 --- a/src/mbgl/style/layers/raster_layer_properties.hpp +++ b/src/mbgl/style/layers/raster_layer_properties.hpp @@ -5,7 +5,9 @@ #include <mbgl/style/types.hpp> #include <mbgl/style/layout_property.hpp> #include <mbgl/style/paint_property.hpp> +#include <mbgl/style/properties.hpp> #include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> namespace mbgl { namespace style { @@ -38,7 +40,7 @@ struct RasterFadeDuration : PaintProperty<float> { static float defaultValue() { return 300; } }; -class RasterPaintProperties : public PaintProperties< +class RasterPaintProperties : public Properties< RasterOpacity, RasterHueRotate, RasterBrightnessMin, diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index 273a9fd24e..9a944657ca 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -2,63 +2,92 @@ #include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/layers/symbol_layer_impl.hpp> -#include <mbgl/style/conversion/stringify.hpp> +#include <mbgl/style/layer_observer.hpp> namespace mbgl { namespace style { SymbolLayer::SymbolLayer(const std::string& layerID, const std::string& sourceID) - : Layer(LayerType::Symbol, std::make_unique<Impl>()) - , impl(static_cast<Impl*>(baseImpl.get())) { - impl->id = layerID; - impl->source = sourceID; + : Layer(makeMutable<Impl>(LayerType::Symbol, layerID, sourceID)) { } -SymbolLayer::SymbolLayer(const Impl& other) - : Layer(LayerType::Symbol, std::make_unique<Impl>(other)) - , impl(static_cast<Impl*>(baseImpl.get())) { +SymbolLayer::SymbolLayer(Immutable<Impl> impl_) + : Layer(std::move(impl_)) { } SymbolLayer::~SymbolLayer() = default; -std::unique_ptr<Layer> SymbolLayer::Impl::clone() const { - return std::make_unique<SymbolLayer>(*this); +const SymbolLayer::Impl& SymbolLayer::impl() const { + return static_cast<const Impl&>(*baseImpl); } -std::unique_ptr<Layer> SymbolLayer::Impl::cloneRef(const std::string& id_) const { - auto result = std::make_unique<SymbolLayer>(*this); - result->impl->id = id_; - result->impl->cascading = SymbolPaintProperties::Cascading(); - return std::move(result); +Mutable<SymbolLayer::Impl> SymbolLayer::mutableImpl() const { + return makeMutable<Impl>(impl()); +} + +std::unique_ptr<Layer> SymbolLayer::cloneRef(const std::string& id_) const { + auto impl_ = mutableImpl(); + impl_->id = id_; + impl_->paint = SymbolPaintProperties::Transitionable(); + return std::make_unique<SymbolLayer>(std::move(impl_)); } void SymbolLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>& writer) const { - conversion::stringify(writer, layout); + layout.stringify(writer); } // Source const std::string& SymbolLayer::getSourceID() const { - return impl->source; + return impl().source; } void SymbolLayer::setSourceLayer(const std::string& sourceLayer) { - impl->sourceLayer = sourceLayer; + auto impl_ = mutableImpl(); + impl_->sourceLayer = sourceLayer; + baseImpl = std::move(impl_); } const std::string& SymbolLayer::getSourceLayer() const { - return impl->sourceLayer; + return impl().sourceLayer; } // Filter void SymbolLayer::setFilter(const Filter& filter) { - impl->filter = filter; - impl->observer->onLayerFilterChanged(*this); + auto impl_ = mutableImpl(); + impl_->filter = filter; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } const Filter& SymbolLayer::getFilter() const { - return impl->filter; + return impl().filter; +} + +// Visibility + +void SymbolLayer::setVisibility(VisibilityType value) { + if (value == getVisibility()) + return; + auto impl_ = mutableImpl(); + impl_->visibility = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +// Zoom range + +void SymbolLayer::setMinZoom(float minZoom) { + auto impl_ = mutableImpl(); + impl_->minZoom = minZoom; + baseImpl = std::move(impl_); +} + +void SymbolLayer::setMaxZoom(float maxZoom) { + auto impl_ = mutableImpl(); + impl_->maxZoom = maxZoom; + baseImpl = std::move(impl_); } // Layout properties @@ -68,476 +97,576 @@ PropertyValue<SymbolPlacementType> SymbolLayer::getDefaultSymbolPlacement() { } PropertyValue<SymbolPlacementType> SymbolLayer::getSymbolPlacement() const { - return impl->layout.unevaluated.get<SymbolPlacement>(); + return impl().layout.get<SymbolPlacement>(); } void SymbolLayer::setSymbolPlacement(PropertyValue<SymbolPlacementType> value) { if (value == getSymbolPlacement()) return; - impl->layout.unevaluated.get<SymbolPlacement>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "symbol-placement"); + auto impl_ = mutableImpl(); + impl_->layout.get<SymbolPlacement>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<float> SymbolLayer::getDefaultSymbolSpacing() { return SymbolSpacing::defaultValue(); } PropertyValue<float> SymbolLayer::getSymbolSpacing() const { - return impl->layout.unevaluated.get<SymbolSpacing>(); + return impl().layout.get<SymbolSpacing>(); } void SymbolLayer::setSymbolSpacing(PropertyValue<float> value) { if (value == getSymbolSpacing()) return; - impl->layout.unevaluated.get<SymbolSpacing>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "symbol-spacing"); + auto impl_ = mutableImpl(); + impl_->layout.get<SymbolSpacing>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<bool> SymbolLayer::getDefaultSymbolAvoidEdges() { return SymbolAvoidEdges::defaultValue(); } PropertyValue<bool> SymbolLayer::getSymbolAvoidEdges() const { - return impl->layout.unevaluated.get<SymbolAvoidEdges>(); + return impl().layout.get<SymbolAvoidEdges>(); } void SymbolLayer::setSymbolAvoidEdges(PropertyValue<bool> value) { if (value == getSymbolAvoidEdges()) return; - impl->layout.unevaluated.get<SymbolAvoidEdges>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "symbol-avoid-edges"); + auto impl_ = mutableImpl(); + impl_->layout.get<SymbolAvoidEdges>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<bool> SymbolLayer::getDefaultIconAllowOverlap() { return IconAllowOverlap::defaultValue(); } PropertyValue<bool> SymbolLayer::getIconAllowOverlap() const { - return impl->layout.unevaluated.get<IconAllowOverlap>(); + return impl().layout.get<IconAllowOverlap>(); } void SymbolLayer::setIconAllowOverlap(PropertyValue<bool> value) { if (value == getIconAllowOverlap()) return; - impl->layout.unevaluated.get<IconAllowOverlap>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "icon-allow-overlap"); + auto impl_ = mutableImpl(); + impl_->layout.get<IconAllowOverlap>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<bool> SymbolLayer::getDefaultIconIgnorePlacement() { return IconIgnorePlacement::defaultValue(); } PropertyValue<bool> SymbolLayer::getIconIgnorePlacement() const { - return impl->layout.unevaluated.get<IconIgnorePlacement>(); + return impl().layout.get<IconIgnorePlacement>(); } void SymbolLayer::setIconIgnorePlacement(PropertyValue<bool> value) { if (value == getIconIgnorePlacement()) return; - impl->layout.unevaluated.get<IconIgnorePlacement>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "icon-ignore-placement"); + auto impl_ = mutableImpl(); + impl_->layout.get<IconIgnorePlacement>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<bool> SymbolLayer::getDefaultIconOptional() { return IconOptional::defaultValue(); } PropertyValue<bool> SymbolLayer::getIconOptional() const { - return impl->layout.unevaluated.get<IconOptional>(); + return impl().layout.get<IconOptional>(); } void SymbolLayer::setIconOptional(PropertyValue<bool> value) { if (value == getIconOptional()) return; - impl->layout.unevaluated.get<IconOptional>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "icon-optional"); + auto impl_ = mutableImpl(); + impl_->layout.get<IconOptional>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<AlignmentType> SymbolLayer::getDefaultIconRotationAlignment() { return IconRotationAlignment::defaultValue(); } PropertyValue<AlignmentType> SymbolLayer::getIconRotationAlignment() const { - return impl->layout.unevaluated.get<IconRotationAlignment>(); + return impl().layout.get<IconRotationAlignment>(); } void SymbolLayer::setIconRotationAlignment(PropertyValue<AlignmentType> value) { if (value == getIconRotationAlignment()) return; - impl->layout.unevaluated.get<IconRotationAlignment>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "icon-rotation-alignment"); + auto impl_ = mutableImpl(); + impl_->layout.get<IconRotationAlignment>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconSize() { return IconSize::defaultValue(); } DataDrivenPropertyValue<float> SymbolLayer::getIconSize() const { - return impl->layout.unevaluated.get<IconSize>(); + return impl().layout.get<IconSize>(); } void SymbolLayer::setIconSize(DataDrivenPropertyValue<float> value) { if (value == getIconSize()) return; - impl->layout.unevaluated.get<IconSize>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "icon-size"); + auto impl_ = mutableImpl(); + impl_->layout.get<IconSize>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<IconTextFitType> SymbolLayer::getDefaultIconTextFit() { return IconTextFit::defaultValue(); } PropertyValue<IconTextFitType> SymbolLayer::getIconTextFit() const { - return impl->layout.unevaluated.get<IconTextFit>(); + return impl().layout.get<IconTextFit>(); } void SymbolLayer::setIconTextFit(PropertyValue<IconTextFitType> value) { if (value == getIconTextFit()) return; - impl->layout.unevaluated.get<IconTextFit>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "icon-text-fit"); + auto impl_ = mutableImpl(); + impl_->layout.get<IconTextFit>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<std::array<float, 4>> SymbolLayer::getDefaultIconTextFitPadding() { return IconTextFitPadding::defaultValue(); } PropertyValue<std::array<float, 4>> SymbolLayer::getIconTextFitPadding() const { - return impl->layout.unevaluated.get<IconTextFitPadding>(); + return impl().layout.get<IconTextFitPadding>(); } void SymbolLayer::setIconTextFitPadding(PropertyValue<std::array<float, 4>> value) { if (value == getIconTextFitPadding()) return; - impl->layout.unevaluated.get<IconTextFitPadding>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "icon-text-fit-padding"); + auto impl_ = mutableImpl(); + impl_->layout.get<IconTextFitPadding>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } DataDrivenPropertyValue<std::string> SymbolLayer::getDefaultIconImage() { return IconImage::defaultValue(); } DataDrivenPropertyValue<std::string> SymbolLayer::getIconImage() const { - return impl->layout.unevaluated.get<IconImage>(); + return impl().layout.get<IconImage>(); } void SymbolLayer::setIconImage(DataDrivenPropertyValue<std::string> value) { if (value == getIconImage()) return; - impl->layout.unevaluated.get<IconImage>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "icon-image"); + auto impl_ = mutableImpl(); + impl_->layout.get<IconImage>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconRotate() { return IconRotate::defaultValue(); } DataDrivenPropertyValue<float> SymbolLayer::getIconRotate() const { - return impl->layout.unevaluated.get<IconRotate>(); + return impl().layout.get<IconRotate>(); } void SymbolLayer::setIconRotate(DataDrivenPropertyValue<float> value) { if (value == getIconRotate()) return; - impl->layout.unevaluated.get<IconRotate>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "icon-rotate"); + auto impl_ = mutableImpl(); + impl_->layout.get<IconRotate>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<float> SymbolLayer::getDefaultIconPadding() { return IconPadding::defaultValue(); } PropertyValue<float> SymbolLayer::getIconPadding() const { - return impl->layout.unevaluated.get<IconPadding>(); + return impl().layout.get<IconPadding>(); } void SymbolLayer::setIconPadding(PropertyValue<float> value) { if (value == getIconPadding()) return; - impl->layout.unevaluated.get<IconPadding>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "icon-padding"); + auto impl_ = mutableImpl(); + impl_->layout.get<IconPadding>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<bool> SymbolLayer::getDefaultIconKeepUpright() { return IconKeepUpright::defaultValue(); } PropertyValue<bool> SymbolLayer::getIconKeepUpright() const { - return impl->layout.unevaluated.get<IconKeepUpright>(); + return impl().layout.get<IconKeepUpright>(); } void SymbolLayer::setIconKeepUpright(PropertyValue<bool> value) { if (value == getIconKeepUpright()) return; - impl->layout.unevaluated.get<IconKeepUpright>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "icon-keep-upright"); + auto impl_ = mutableImpl(); + impl_->layout.get<IconKeepUpright>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } DataDrivenPropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconOffset() { return IconOffset::defaultValue(); } DataDrivenPropertyValue<std::array<float, 2>> SymbolLayer::getIconOffset() const { - return impl->layout.unevaluated.get<IconOffset>(); + return impl().layout.get<IconOffset>(); } void SymbolLayer::setIconOffset(DataDrivenPropertyValue<std::array<float, 2>> value) { if (value == getIconOffset()) return; - impl->layout.unevaluated.get<IconOffset>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "icon-offset"); + auto impl_ = mutableImpl(); + impl_->layout.get<IconOffset>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} +DataDrivenPropertyValue<SymbolAnchorType> SymbolLayer::getDefaultIconAnchor() { + return IconAnchor::defaultValue(); +} + +DataDrivenPropertyValue<SymbolAnchorType> SymbolLayer::getIconAnchor() const { + return impl().layout.get<IconAnchor>(); +} + +void SymbolLayer::setIconAnchor(DataDrivenPropertyValue<SymbolAnchorType> value) { + if (value == getIconAnchor()) + return; + auto impl_ = mutableImpl(); + impl_->layout.get<IconAnchor>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} +PropertyValue<AlignmentType> SymbolLayer::getDefaultIconPitchAlignment() { + return IconPitchAlignment::defaultValue(); +} + +PropertyValue<AlignmentType> SymbolLayer::getIconPitchAlignment() const { + return impl().layout.get<IconPitchAlignment>(); +} + +void SymbolLayer::setIconPitchAlignment(PropertyValue<AlignmentType> value) { + if (value == getIconPitchAlignment()) + return; + auto impl_ = mutableImpl(); + impl_->layout.get<IconPitchAlignment>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<AlignmentType> SymbolLayer::getDefaultTextPitchAlignment() { return TextPitchAlignment::defaultValue(); } PropertyValue<AlignmentType> SymbolLayer::getTextPitchAlignment() const { - return impl->layout.unevaluated.get<TextPitchAlignment>(); + return impl().layout.get<TextPitchAlignment>(); } void SymbolLayer::setTextPitchAlignment(PropertyValue<AlignmentType> value) { if (value == getTextPitchAlignment()) return; - impl->layout.unevaluated.get<TextPitchAlignment>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-pitch-alignment"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextPitchAlignment>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<AlignmentType> SymbolLayer::getDefaultTextRotationAlignment() { return TextRotationAlignment::defaultValue(); } PropertyValue<AlignmentType> SymbolLayer::getTextRotationAlignment() const { - return impl->layout.unevaluated.get<TextRotationAlignment>(); + return impl().layout.get<TextRotationAlignment>(); } void SymbolLayer::setTextRotationAlignment(PropertyValue<AlignmentType> value) { if (value == getTextRotationAlignment()) return; - impl->layout.unevaluated.get<TextRotationAlignment>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-rotation-alignment"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextRotationAlignment>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } DataDrivenPropertyValue<std::string> SymbolLayer::getDefaultTextField() { return TextField::defaultValue(); } DataDrivenPropertyValue<std::string> SymbolLayer::getTextField() const { - return impl->layout.unevaluated.get<TextField>(); + return impl().layout.get<TextField>(); } void SymbolLayer::setTextField(DataDrivenPropertyValue<std::string> value) { if (value == getTextField()) return; - impl->layout.unevaluated.get<TextField>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-field"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextField>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<std::vector<std::string>> SymbolLayer::getDefaultTextFont() { return TextFont::defaultValue(); } PropertyValue<std::vector<std::string>> SymbolLayer::getTextFont() const { - return impl->layout.unevaluated.get<TextFont>(); + return impl().layout.get<TextFont>(); } void SymbolLayer::setTextFont(PropertyValue<std::vector<std::string>> value) { if (value == getTextFont()) return; - impl->layout.unevaluated.get<TextFont>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-font"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextFont>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextSize() { return TextSize::defaultValue(); } DataDrivenPropertyValue<float> SymbolLayer::getTextSize() const { - return impl->layout.unevaluated.get<TextSize>(); + return impl().layout.get<TextSize>(); } void SymbolLayer::setTextSize(DataDrivenPropertyValue<float> value) { if (value == getTextSize()) return; - impl->layout.unevaluated.get<TextSize>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-size"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextSize>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -PropertyValue<float> SymbolLayer::getDefaultTextMaxWidth() { +DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextMaxWidth() { return TextMaxWidth::defaultValue(); } -PropertyValue<float> SymbolLayer::getTextMaxWidth() const { - return impl->layout.unevaluated.get<TextMaxWidth>(); +DataDrivenPropertyValue<float> SymbolLayer::getTextMaxWidth() const { + return impl().layout.get<TextMaxWidth>(); } -void SymbolLayer::setTextMaxWidth(PropertyValue<float> value) { +void SymbolLayer::setTextMaxWidth(DataDrivenPropertyValue<float> value) { if (value == getTextMaxWidth()) return; - impl->layout.unevaluated.get<TextMaxWidth>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-max-width"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextMaxWidth>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<float> SymbolLayer::getDefaultTextLineHeight() { return TextLineHeight::defaultValue(); } PropertyValue<float> SymbolLayer::getTextLineHeight() const { - return impl->layout.unevaluated.get<TextLineHeight>(); + return impl().layout.get<TextLineHeight>(); } void SymbolLayer::setTextLineHeight(PropertyValue<float> value) { if (value == getTextLineHeight()) return; - impl->layout.unevaluated.get<TextLineHeight>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-line-height"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextLineHeight>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -PropertyValue<float> SymbolLayer::getDefaultTextLetterSpacing() { +DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextLetterSpacing() { return TextLetterSpacing::defaultValue(); } -PropertyValue<float> SymbolLayer::getTextLetterSpacing() const { - return impl->layout.unevaluated.get<TextLetterSpacing>(); +DataDrivenPropertyValue<float> SymbolLayer::getTextLetterSpacing() const { + return impl().layout.get<TextLetterSpacing>(); } -void SymbolLayer::setTextLetterSpacing(PropertyValue<float> value) { +void SymbolLayer::setTextLetterSpacing(DataDrivenPropertyValue<float> value) { if (value == getTextLetterSpacing()) return; - impl->layout.unevaluated.get<TextLetterSpacing>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-letter-spacing"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextLetterSpacing>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -PropertyValue<TextJustifyType> SymbolLayer::getDefaultTextJustify() { +DataDrivenPropertyValue<TextJustifyType> SymbolLayer::getDefaultTextJustify() { return TextJustify::defaultValue(); } -PropertyValue<TextJustifyType> SymbolLayer::getTextJustify() const { - return impl->layout.unevaluated.get<TextJustify>(); +DataDrivenPropertyValue<TextJustifyType> SymbolLayer::getTextJustify() const { + return impl().layout.get<TextJustify>(); } -void SymbolLayer::setTextJustify(PropertyValue<TextJustifyType> value) { +void SymbolLayer::setTextJustify(DataDrivenPropertyValue<TextJustifyType> value) { if (value == getTextJustify()) return; - impl->layout.unevaluated.get<TextJustify>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-justify"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextJustify>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -PropertyValue<TextAnchorType> SymbolLayer::getDefaultTextAnchor() { +DataDrivenPropertyValue<SymbolAnchorType> SymbolLayer::getDefaultTextAnchor() { return TextAnchor::defaultValue(); } -PropertyValue<TextAnchorType> SymbolLayer::getTextAnchor() const { - return impl->layout.unevaluated.get<TextAnchor>(); +DataDrivenPropertyValue<SymbolAnchorType> SymbolLayer::getTextAnchor() const { + return impl().layout.get<TextAnchor>(); } -void SymbolLayer::setTextAnchor(PropertyValue<TextAnchorType> value) { +void SymbolLayer::setTextAnchor(DataDrivenPropertyValue<SymbolAnchorType> value) { if (value == getTextAnchor()) return; - impl->layout.unevaluated.get<TextAnchor>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-anchor"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextAnchor>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<float> SymbolLayer::getDefaultTextMaxAngle() { return TextMaxAngle::defaultValue(); } PropertyValue<float> SymbolLayer::getTextMaxAngle() const { - return impl->layout.unevaluated.get<TextMaxAngle>(); + return impl().layout.get<TextMaxAngle>(); } void SymbolLayer::setTextMaxAngle(PropertyValue<float> value) { if (value == getTextMaxAngle()) return; - impl->layout.unevaluated.get<TextMaxAngle>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-max-angle"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextMaxAngle>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextRotate() { return TextRotate::defaultValue(); } DataDrivenPropertyValue<float> SymbolLayer::getTextRotate() const { - return impl->layout.unevaluated.get<TextRotate>(); + return impl().layout.get<TextRotate>(); } void SymbolLayer::setTextRotate(DataDrivenPropertyValue<float> value) { if (value == getTextRotate()) return; - impl->layout.unevaluated.get<TextRotate>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-rotate"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextRotate>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<float> SymbolLayer::getDefaultTextPadding() { return TextPadding::defaultValue(); } PropertyValue<float> SymbolLayer::getTextPadding() const { - return impl->layout.unevaluated.get<TextPadding>(); + return impl().layout.get<TextPadding>(); } void SymbolLayer::setTextPadding(PropertyValue<float> value) { if (value == getTextPadding()) return; - impl->layout.unevaluated.get<TextPadding>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-padding"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextPadding>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<bool> SymbolLayer::getDefaultTextKeepUpright() { return TextKeepUpright::defaultValue(); } PropertyValue<bool> SymbolLayer::getTextKeepUpright() const { - return impl->layout.unevaluated.get<TextKeepUpright>(); + return impl().layout.get<TextKeepUpright>(); } void SymbolLayer::setTextKeepUpright(PropertyValue<bool> value) { if (value == getTextKeepUpright()) return; - impl->layout.unevaluated.get<TextKeepUpright>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-keep-upright"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextKeepUpright>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } DataDrivenPropertyValue<TextTransformType> SymbolLayer::getDefaultTextTransform() { return TextTransform::defaultValue(); } DataDrivenPropertyValue<TextTransformType> SymbolLayer::getTextTransform() const { - return impl->layout.unevaluated.get<TextTransform>(); + return impl().layout.get<TextTransform>(); } void SymbolLayer::setTextTransform(DataDrivenPropertyValue<TextTransformType> value) { if (value == getTextTransform()) return; - impl->layout.unevaluated.get<TextTransform>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-transform"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextTransform>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } DataDrivenPropertyValue<std::array<float, 2>> SymbolLayer::getDefaultTextOffset() { return TextOffset::defaultValue(); } DataDrivenPropertyValue<std::array<float, 2>> SymbolLayer::getTextOffset() const { - return impl->layout.unevaluated.get<TextOffset>(); + return impl().layout.get<TextOffset>(); } void SymbolLayer::setTextOffset(DataDrivenPropertyValue<std::array<float, 2>> value) { if (value == getTextOffset()) return; - impl->layout.unevaluated.get<TextOffset>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-offset"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextOffset>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<bool> SymbolLayer::getDefaultTextAllowOverlap() { return TextAllowOverlap::defaultValue(); } PropertyValue<bool> SymbolLayer::getTextAllowOverlap() const { - return impl->layout.unevaluated.get<TextAllowOverlap>(); + return impl().layout.get<TextAllowOverlap>(); } void SymbolLayer::setTextAllowOverlap(PropertyValue<bool> value) { if (value == getTextAllowOverlap()) return; - impl->layout.unevaluated.get<TextAllowOverlap>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-allow-overlap"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextAllowOverlap>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<bool> SymbolLayer::getDefaultTextIgnorePlacement() { return TextIgnorePlacement::defaultValue(); } PropertyValue<bool> SymbolLayer::getTextIgnorePlacement() const { - return impl->layout.unevaluated.get<TextIgnorePlacement>(); + return impl().layout.get<TextIgnorePlacement>(); } void SymbolLayer::setTextIgnorePlacement(PropertyValue<bool> value) { if (value == getTextIgnorePlacement()) return; - impl->layout.unevaluated.get<TextIgnorePlacement>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-ignore-placement"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextIgnorePlacement>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } PropertyValue<bool> SymbolLayer::getDefaultTextOptional() { return TextOptional::defaultValue(); } PropertyValue<bool> SymbolLayer::getTextOptional() const { - return impl->layout.unevaluated.get<TextOptional>(); + return impl().layout.get<TextOptional>(); } void SymbolLayer::setTextOptional(PropertyValue<bool> value) { if (value == getTextOptional()) return; - impl->layout.unevaluated.get<TextOptional>() = value; - impl->observer->onLayerLayoutPropertyChanged(*this, "text-optional"); + auto impl_ = mutableImpl(); + impl_->layout.get<TextOptional>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } // Paint properties @@ -546,362 +675,378 @@ DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconOpacity() { return { 1 }; } -DataDrivenPropertyValue<float> SymbolLayer::getIconOpacity(const optional<std::string>& klass) const { - return impl->cascading.template get<IconOpacity>().get(klass); +DataDrivenPropertyValue<float> SymbolLayer::getIconOpacity() const { + return impl().paint.template get<IconOpacity>().value; } -void SymbolLayer::setIconOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getIconOpacity(klass)) +void SymbolLayer::setIconOpacity(DataDrivenPropertyValue<float> value) { + if (value == getIconOpacity()) return; - impl->cascading.template get<IconOpacity>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<IconOpacity>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void SymbolLayer::setIconOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<IconOpacity>().setTransition(value, klass); +void SymbolLayer::setIconOpacityTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<IconOpacity>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions SymbolLayer::getIconOpacityTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<IconOpacity>().getTransition(klass); +TransitionOptions SymbolLayer::getIconOpacityTransition() const { + return impl().paint.template get<IconOpacity>().options; } DataDrivenPropertyValue<Color> SymbolLayer::getDefaultIconColor() { return { Color::black() }; } -DataDrivenPropertyValue<Color> SymbolLayer::getIconColor(const optional<std::string>& klass) const { - return impl->cascading.template get<IconColor>().get(klass); +DataDrivenPropertyValue<Color> SymbolLayer::getIconColor() const { + return impl().paint.template get<IconColor>().value; } -void SymbolLayer::setIconColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { - if (value == getIconColor(klass)) +void SymbolLayer::setIconColor(DataDrivenPropertyValue<Color> value) { + if (value == getIconColor()) return; - impl->cascading.template get<IconColor>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<IconColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void SymbolLayer::setIconColorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<IconColor>().setTransition(value, klass); +void SymbolLayer::setIconColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<IconColor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions SymbolLayer::getIconColorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<IconColor>().getTransition(klass); +TransitionOptions SymbolLayer::getIconColorTransition() const { + return impl().paint.template get<IconColor>().options; } DataDrivenPropertyValue<Color> SymbolLayer::getDefaultIconHaloColor() { return { {} }; } -DataDrivenPropertyValue<Color> SymbolLayer::getIconHaloColor(const optional<std::string>& klass) const { - return impl->cascading.template get<IconHaloColor>().get(klass); +DataDrivenPropertyValue<Color> SymbolLayer::getIconHaloColor() const { + return impl().paint.template get<IconHaloColor>().value; } -void SymbolLayer::setIconHaloColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { - if (value == getIconHaloColor(klass)) +void SymbolLayer::setIconHaloColor(DataDrivenPropertyValue<Color> value) { + if (value == getIconHaloColor()) return; - impl->cascading.template get<IconHaloColor>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<IconHaloColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void SymbolLayer::setIconHaloColorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<IconHaloColor>().setTransition(value, klass); +void SymbolLayer::setIconHaloColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<IconHaloColor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions SymbolLayer::getIconHaloColorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<IconHaloColor>().getTransition(klass); +TransitionOptions SymbolLayer::getIconHaloColorTransition() const { + return impl().paint.template get<IconHaloColor>().options; } DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconHaloWidth() { return { 0 }; } -DataDrivenPropertyValue<float> SymbolLayer::getIconHaloWidth(const optional<std::string>& klass) const { - return impl->cascading.template get<IconHaloWidth>().get(klass); +DataDrivenPropertyValue<float> SymbolLayer::getIconHaloWidth() const { + return impl().paint.template get<IconHaloWidth>().value; } -void SymbolLayer::setIconHaloWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getIconHaloWidth(klass)) +void SymbolLayer::setIconHaloWidth(DataDrivenPropertyValue<float> value) { + if (value == getIconHaloWidth()) return; - impl->cascading.template get<IconHaloWidth>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<IconHaloWidth>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void SymbolLayer::setIconHaloWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<IconHaloWidth>().setTransition(value, klass); +void SymbolLayer::setIconHaloWidthTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<IconHaloWidth>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions SymbolLayer::getIconHaloWidthTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<IconHaloWidth>().getTransition(klass); +TransitionOptions SymbolLayer::getIconHaloWidthTransition() const { + return impl().paint.template get<IconHaloWidth>().options; } DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconHaloBlur() { return { 0 }; } -DataDrivenPropertyValue<float> SymbolLayer::getIconHaloBlur(const optional<std::string>& klass) const { - return impl->cascading.template get<IconHaloBlur>().get(klass); +DataDrivenPropertyValue<float> SymbolLayer::getIconHaloBlur() const { + return impl().paint.template get<IconHaloBlur>().value; } -void SymbolLayer::setIconHaloBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getIconHaloBlur(klass)) +void SymbolLayer::setIconHaloBlur(DataDrivenPropertyValue<float> value) { + if (value == getIconHaloBlur()) return; - impl->cascading.template get<IconHaloBlur>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<IconHaloBlur>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void SymbolLayer::setIconHaloBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<IconHaloBlur>().setTransition(value, klass); +void SymbolLayer::setIconHaloBlurTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<IconHaloBlur>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions SymbolLayer::getIconHaloBlurTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<IconHaloBlur>().getTransition(klass); +TransitionOptions SymbolLayer::getIconHaloBlurTransition() const { + return impl().paint.template get<IconHaloBlur>().options; } PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconTranslate() { return { {{ 0, 0 }} }; } -PropertyValue<std::array<float, 2>> SymbolLayer::getIconTranslate(const optional<std::string>& klass) const { - return impl->cascading.template get<IconTranslate>().get(klass); +PropertyValue<std::array<float, 2>> SymbolLayer::getIconTranslate() const { + return impl().paint.template get<IconTranslate>().value; } -void SymbolLayer::setIconTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) { - if (value == getIconTranslate(klass)) +void SymbolLayer::setIconTranslate(PropertyValue<std::array<float, 2>> value) { + if (value == getIconTranslate()) return; - impl->cascading.template get<IconTranslate>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<IconTranslate>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void SymbolLayer::setIconTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<IconTranslate>().setTransition(value, klass); +void SymbolLayer::setIconTranslateTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<IconTranslate>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions SymbolLayer::getIconTranslateTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<IconTranslate>().getTransition(klass); +TransitionOptions SymbolLayer::getIconTranslateTransition() const { + return impl().paint.template get<IconTranslate>().options; } PropertyValue<TranslateAnchorType> SymbolLayer::getDefaultIconTranslateAnchor() { return { TranslateAnchorType::Map }; } -PropertyValue<TranslateAnchorType> SymbolLayer::getIconTranslateAnchor(const optional<std::string>& klass) const { - return impl->cascading.template get<IconTranslateAnchor>().get(klass); +PropertyValue<TranslateAnchorType> SymbolLayer::getIconTranslateAnchor() const { + return impl().paint.template get<IconTranslateAnchor>().value; } -void SymbolLayer::setIconTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) { - if (value == getIconTranslateAnchor(klass)) +void SymbolLayer::setIconTranslateAnchor(PropertyValue<TranslateAnchorType> value) { + if (value == getIconTranslateAnchor()) return; - impl->cascading.template get<IconTranslateAnchor>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<IconTranslateAnchor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void SymbolLayer::setIconTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<IconTranslateAnchor>().setTransition(value, klass); +void SymbolLayer::setIconTranslateAnchorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<IconTranslateAnchor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions SymbolLayer::getIconTranslateAnchorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<IconTranslateAnchor>().getTransition(klass); +TransitionOptions SymbolLayer::getIconTranslateAnchorTransition() const { + return impl().paint.template get<IconTranslateAnchor>().options; } DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextOpacity() { return { 1 }; } -DataDrivenPropertyValue<float> SymbolLayer::getTextOpacity(const optional<std::string>& klass) const { - return impl->cascading.template get<TextOpacity>().get(klass); +DataDrivenPropertyValue<float> SymbolLayer::getTextOpacity() const { + return impl().paint.template get<TextOpacity>().value; } -void SymbolLayer::setTextOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getTextOpacity(klass)) +void SymbolLayer::setTextOpacity(DataDrivenPropertyValue<float> value) { + if (value == getTextOpacity()) return; - impl->cascading.template get<TextOpacity>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<TextOpacity>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void SymbolLayer::setTextOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<TextOpacity>().setTransition(value, klass); +void SymbolLayer::setTextOpacityTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<TextOpacity>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions SymbolLayer::getTextOpacityTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<TextOpacity>().getTransition(klass); +TransitionOptions SymbolLayer::getTextOpacityTransition() const { + return impl().paint.template get<TextOpacity>().options; } DataDrivenPropertyValue<Color> SymbolLayer::getDefaultTextColor() { return { Color::black() }; } -DataDrivenPropertyValue<Color> SymbolLayer::getTextColor(const optional<std::string>& klass) const { - return impl->cascading.template get<TextColor>().get(klass); +DataDrivenPropertyValue<Color> SymbolLayer::getTextColor() const { + return impl().paint.template get<TextColor>().value; } -void SymbolLayer::setTextColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { - if (value == getTextColor(klass)) +void SymbolLayer::setTextColor(DataDrivenPropertyValue<Color> value) { + if (value == getTextColor()) return; - impl->cascading.template get<TextColor>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<TextColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void SymbolLayer::setTextColorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<TextColor>().setTransition(value, klass); +void SymbolLayer::setTextColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<TextColor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions SymbolLayer::getTextColorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<TextColor>().getTransition(klass); +TransitionOptions SymbolLayer::getTextColorTransition() const { + return impl().paint.template get<TextColor>().options; } DataDrivenPropertyValue<Color> SymbolLayer::getDefaultTextHaloColor() { return { {} }; } -DataDrivenPropertyValue<Color> SymbolLayer::getTextHaloColor(const optional<std::string>& klass) const { - return impl->cascading.template get<TextHaloColor>().get(klass); +DataDrivenPropertyValue<Color> SymbolLayer::getTextHaloColor() const { + return impl().paint.template get<TextHaloColor>().value; } -void SymbolLayer::setTextHaloColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { - if (value == getTextHaloColor(klass)) +void SymbolLayer::setTextHaloColor(DataDrivenPropertyValue<Color> value) { + if (value == getTextHaloColor()) return; - impl->cascading.template get<TextHaloColor>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<TextHaloColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void SymbolLayer::setTextHaloColorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<TextHaloColor>().setTransition(value, klass); +void SymbolLayer::setTextHaloColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<TextHaloColor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions SymbolLayer::getTextHaloColorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<TextHaloColor>().getTransition(klass); +TransitionOptions SymbolLayer::getTextHaloColorTransition() const { + return impl().paint.template get<TextHaloColor>().options; } DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextHaloWidth() { return { 0 }; } -DataDrivenPropertyValue<float> SymbolLayer::getTextHaloWidth(const optional<std::string>& klass) const { - return impl->cascading.template get<TextHaloWidth>().get(klass); +DataDrivenPropertyValue<float> SymbolLayer::getTextHaloWidth() const { + return impl().paint.template get<TextHaloWidth>().value; } -void SymbolLayer::setTextHaloWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getTextHaloWidth(klass)) +void SymbolLayer::setTextHaloWidth(DataDrivenPropertyValue<float> value) { + if (value == getTextHaloWidth()) return; - impl->cascading.template get<TextHaloWidth>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<TextHaloWidth>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void SymbolLayer::setTextHaloWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<TextHaloWidth>().setTransition(value, klass); +void SymbolLayer::setTextHaloWidthTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<TextHaloWidth>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions SymbolLayer::getTextHaloWidthTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<TextHaloWidth>().getTransition(klass); +TransitionOptions SymbolLayer::getTextHaloWidthTransition() const { + return impl().paint.template get<TextHaloWidth>().options; } DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextHaloBlur() { return { 0 }; } -DataDrivenPropertyValue<float> SymbolLayer::getTextHaloBlur(const optional<std::string>& klass) const { - return impl->cascading.template get<TextHaloBlur>().get(klass); +DataDrivenPropertyValue<float> SymbolLayer::getTextHaloBlur() const { + return impl().paint.template get<TextHaloBlur>().value; } -void SymbolLayer::setTextHaloBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { - if (value == getTextHaloBlur(klass)) +void SymbolLayer::setTextHaloBlur(DataDrivenPropertyValue<float> value) { + if (value == getTextHaloBlur()) return; - impl->cascading.template get<TextHaloBlur>().set(value, klass); - if (value.isDataDriven()) { - impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); - } else { - impl->observer->onLayerPaintPropertyChanged(*this); - } + auto impl_ = mutableImpl(); + impl_->paint.template get<TextHaloBlur>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void SymbolLayer::setTextHaloBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<TextHaloBlur>().setTransition(value, klass); +void SymbolLayer::setTextHaloBlurTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<TextHaloBlur>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions SymbolLayer::getTextHaloBlurTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<TextHaloBlur>().getTransition(klass); +TransitionOptions SymbolLayer::getTextHaloBlurTransition() const { + return impl().paint.template get<TextHaloBlur>().options; } PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultTextTranslate() { return { {{ 0, 0 }} }; } -PropertyValue<std::array<float, 2>> SymbolLayer::getTextTranslate(const optional<std::string>& klass) const { - return impl->cascading.template get<TextTranslate>().get(klass); +PropertyValue<std::array<float, 2>> SymbolLayer::getTextTranslate() const { + return impl().paint.template get<TextTranslate>().value; } -void SymbolLayer::setTextTranslate(PropertyValue<std::array<float, 2>> value, const optional<std::string>& klass) { - if (value == getTextTranslate(klass)) +void SymbolLayer::setTextTranslate(PropertyValue<std::array<float, 2>> value) { + if (value == getTextTranslate()) return; - impl->cascading.template get<TextTranslate>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<TextTranslate>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void SymbolLayer::setTextTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<TextTranslate>().setTransition(value, klass); +void SymbolLayer::setTextTranslateTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<TextTranslate>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions SymbolLayer::getTextTranslateTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<TextTranslate>().getTransition(klass); +TransitionOptions SymbolLayer::getTextTranslateTransition() const { + return impl().paint.template get<TextTranslate>().options; } PropertyValue<TranslateAnchorType> SymbolLayer::getDefaultTextTranslateAnchor() { return { TranslateAnchorType::Map }; } -PropertyValue<TranslateAnchorType> SymbolLayer::getTextTranslateAnchor(const optional<std::string>& klass) const { - return impl->cascading.template get<TextTranslateAnchor>().get(klass); +PropertyValue<TranslateAnchorType> SymbolLayer::getTextTranslateAnchor() const { + return impl().paint.template get<TextTranslateAnchor>().value; } -void SymbolLayer::setTextTranslateAnchor(PropertyValue<TranslateAnchorType> value, const optional<std::string>& klass) { - if (value == getTextTranslateAnchor(klass)) +void SymbolLayer::setTextTranslateAnchor(PropertyValue<TranslateAnchorType> value) { + if (value == getTextTranslateAnchor()) return; - impl->cascading.template get<TextTranslateAnchor>().set(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + auto impl_ = mutableImpl(); + impl_->paint.template get<TextTranslateAnchor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); } -void SymbolLayer::setTextTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) { - impl->cascading.template get<TextTranslateAnchor>().setTransition(value, klass); +void SymbolLayer::setTextTranslateAnchorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<TextTranslateAnchor>().options = options; + baseImpl = std::move(impl_); } -TransitionOptions SymbolLayer::getTextTranslateAnchorTransition(const optional<std::string>& klass) const { - return impl->cascading.template get<TextTranslateAnchor>().getTransition(klass); +TransitionOptions SymbolLayer::getTextTranslateAnchorTransition() const { + return impl().paint.template get<TextTranslateAnchor>().options; } } // namespace style diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp index c99dd8ad70..b59768725d 100644 --- a/src/mbgl/style/layers/symbol_layer_impl.cpp +++ b/src/mbgl/style/layers/symbol_layer_impl.cpp @@ -1,11 +1,15 @@ #include <mbgl/style/layers/symbol_layer_impl.hpp> -#include <mbgl/renderer/render_symbol_layer.hpp> namespace mbgl { namespace style { -std::unique_ptr<RenderLayer> SymbolLayer::Impl::createRenderLayer() const { - return std::make_unique<RenderSymbolLayer>(*this); +bool SymbolLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const { + assert(dynamic_cast<const SymbolLayer::Impl*>(&other)); + const auto& impl = static_cast<const style::SymbolLayer::Impl&>(other); + return filter != impl.filter || + visibility != impl.visibility || + layout != impl.layout || + paint.hasDataDrivenPropertyDifference(impl.paint); } } // namespace style diff --git a/src/mbgl/style/layers/symbol_layer_impl.hpp b/src/mbgl/style/layers/symbol_layer_impl.hpp index df145647a0..f8ef87dcdf 100644 --- a/src/mbgl/style/layers/symbol_layer_impl.hpp +++ b/src/mbgl/style/layers/symbol_layer_impl.hpp @@ -1,24 +1,21 @@ #pragma once -#include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/style/layer_impl.hpp> #include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/layers/symbol_layer_properties.hpp> namespace mbgl { - namespace style { class SymbolLayer::Impl : public Layer::Impl { public: - std::unique_ptr<Layer> clone() const override; - std::unique_ptr<Layer> cloneRef(const std::string& id) const override; - void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; + using Layer::Impl::Impl; - std::unique_ptr<RenderLayer> createRenderLayer() const override; + bool hasLayoutDifference(const Layer::Impl&) const override; + void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; - SymbolLayoutProperties layout; - SymbolPaintProperties::Cascading cascading; + SymbolLayoutProperties::Unevaluated layout; + SymbolPaintProperties::Transitionable paint; }; } // namespace style diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp index 5b57175785..436b5cbd4f 100644 --- a/src/mbgl/style/layers/symbol_layer_properties.hpp +++ b/src/mbgl/style/layers/symbol_layer_properties.hpp @@ -5,6 +5,7 @@ #include <mbgl/style/types.hpp> #include <mbgl/style/layout_property.hpp> #include <mbgl/style/paint_property.hpp> +#include <mbgl/style/properties.hpp> #include <mbgl/programs/attributes.hpp> #include <mbgl/programs/uniforms.hpp> @@ -86,6 +87,16 @@ struct IconOffset : DataDrivenLayoutProperty<std::array<float, 2>> { static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; } }; +struct IconAnchor : DataDrivenLayoutProperty<SymbolAnchorType> { + static constexpr const char * key = "icon-anchor"; + static SymbolAnchorType defaultValue() { return SymbolAnchorType::Center; } +}; + +struct IconPitchAlignment : LayoutProperty<AlignmentType> { + static constexpr const char * key = "icon-pitch-alignment"; + static AlignmentType defaultValue() { return AlignmentType::Auto; } +}; + struct TextPitchAlignment : LayoutProperty<AlignmentType> { static constexpr const char * key = "text-pitch-alignment"; static AlignmentType defaultValue() { return AlignmentType::Auto; } @@ -111,7 +122,7 @@ struct TextSize : DataDrivenLayoutProperty<float> { static float defaultValue() { return 16; } }; -struct TextMaxWidth : LayoutProperty<float> { +struct TextMaxWidth : DataDrivenLayoutProperty<float> { static constexpr const char * key = "text-max-width"; static float defaultValue() { return 10; } }; @@ -121,19 +132,19 @@ struct TextLineHeight : LayoutProperty<float> { static float defaultValue() { return 1.2; } }; -struct TextLetterSpacing : LayoutProperty<float> { +struct TextLetterSpacing : DataDrivenLayoutProperty<float> { static constexpr const char * key = "text-letter-spacing"; static float defaultValue() { return 0; } }; -struct TextJustify : LayoutProperty<TextJustifyType> { +struct TextJustify : DataDrivenLayoutProperty<TextJustifyType> { static constexpr const char * key = "text-justify"; static TextJustifyType defaultValue() { return TextJustifyType::Center; } }; -struct TextAnchor : LayoutProperty<TextAnchorType> { +struct TextAnchor : DataDrivenLayoutProperty<SymbolAnchorType> { static constexpr const char * key = "text-anchor"; - static TextAnchorType defaultValue() { return TextAnchorType::Center; } + static SymbolAnchorType defaultValue() { return SymbolAnchorType::Center; } }; struct TextMaxAngle : LayoutProperty<float> { @@ -237,7 +248,7 @@ struct TextTranslateAnchor : PaintProperty<TranslateAnchorType> { static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; } }; -class SymbolLayoutProperties : public LayoutProperties< +class SymbolLayoutProperties : public Properties< SymbolPlacement, SymbolSpacing, SymbolAvoidEdges, @@ -253,6 +264,8 @@ class SymbolLayoutProperties : public LayoutProperties< IconPadding, IconKeepUpright, IconOffset, + IconAnchor, + IconPitchAlignment, TextPitchAlignment, TextRotationAlignment, TextField, @@ -274,7 +287,7 @@ class SymbolLayoutProperties : public LayoutProperties< TextOptional > {}; -class SymbolPaintProperties : public PaintProperties< +class SymbolPaintProperties : public Properties< IconOpacity, IconColor, IconHaloColor, diff --git a/src/mbgl/style/layout_property.hpp b/src/mbgl/style/layout_property.hpp index 3b9d6114c0..8c59295ad2 100644 --- a/src/mbgl/style/layout_property.hpp +++ b/src/mbgl/style/layout_property.hpp @@ -4,117 +4,30 @@ #include <mbgl/style/data_driven_property_value.hpp> #include <mbgl/renderer/property_evaluator.hpp> #include <mbgl/renderer/data_driven_property_evaluator.hpp> -#include <mbgl/util/indexed_tuple.hpp> namespace mbgl { - -class PropertyEvaluationParameters; - namespace style { template <class T> class LayoutProperty { public: + using TransitionableType = std::nullptr_t; using UnevaluatedType = PropertyValue<T>; using EvaluatorType = PropertyEvaluator<T>; using PossiblyEvaluatedType = T; using Type = T; + static constexpr bool IsDataDriven = false; }; template <class T> class DataDrivenLayoutProperty { public: + using TransitionableType = std::nullptr_t; using UnevaluatedType = DataDrivenPropertyValue<T>; using EvaluatorType = DataDrivenPropertyEvaluator<T>; using PossiblyEvaluatedType = PossiblyEvaluatedPropertyValue<T>; using Type = T; -}; - -template <class... Ps> -class LayoutProperties { -public: - using Properties = TypeList<Ps...>; - - template <class TypeList> - using Tuple = IndexedTuple<Properties, TypeList>; - - /* - For layout properties we implement a two step evaluation process: if you have a zoom level, - you can evaluate a set of unevaluated property values, producing a set of possibly evaluated - values, where undefined, constant, or camera function values have been fully evaluated, and - source or composite function values have not. - - Once you also have a particular feature, you can evaluate that set of possibly evaluated values - fully, producing a set of fully evaluated values. - - This is in theory maximally efficient in terms of avoiding repeated evaluation of camera - functions, though it's more of a historical accident than a purposeful optimization. - */ - - using UnevaluatedTypes = TypeList<typename Ps::UnevaluatedType...>; - using PossiblyEvaluatedTypes = TypeList<typename Ps::PossiblyEvaluatedType...>; - using EvaluatedTypes = TypeList<typename Ps::Type...>; - - class Evaluated : public Tuple<EvaluatedTypes> { - public: - using Tuple<EvaluatedTypes>::Tuple; - }; - - class PossiblyEvaluated : public Tuple<PossiblyEvaluatedTypes> { - public: - using Tuple<PossiblyEvaluatedTypes>::Tuple; - - template <class T> - static T evaluate(float, const GeometryTileFeature&, const T& t, const T&) { - return t; - } - - template <class T> - static T evaluate(float z, const GeometryTileFeature& feature, - const PossiblyEvaluatedPropertyValue<T>& v, const T& defaultValue) { - return v.match( - [&] (const T& t) { - return t; - }, - [&] (const SourceFunction<T>& t) { - return t.evaluate(feature, defaultValue); - }, - [&] (const CompositeFunction<T>& t) { - return t.evaluate(z, feature, defaultValue); - }); - } - - template <class P> - auto evaluate(float z, const GeometryTileFeature& feature) const { - return evaluate(z, feature, this->template get<P>(), P::defaultValue()); - } - - Evaluated evaluate(float z, const GeometryTileFeature& feature) const { - return Evaluated { - evaluate<Ps>(z, feature)... - }; - } - }; - - class Unevaluated : public Tuple<UnevaluatedTypes> { - public: - using Tuple<UnevaluatedTypes>::Tuple; - }; - - template <class P> - auto evaluate(const PropertyEvaluationParameters& parameters) const { - using Evaluator = typename P::EvaluatorType; - return unevaluated.template get<P>() - .evaluate(Evaluator(parameters, P::defaultValue())); - } - - PossiblyEvaluated evaluate(const PropertyEvaluationParameters& parameters) const { - return PossiblyEvaluated { - evaluate<Ps>(parameters)... - }; - } - - Unevaluated unevaluated; + static constexpr bool IsDataDriven = true; }; } // namespace style diff --git a/src/mbgl/style/light.cpp b/src/mbgl/style/light.cpp index b54920713c..352dc4d942 100644 --- a/src/mbgl/style/light.cpp +++ b/src/mbgl/style/light.cpp @@ -2,17 +2,28 @@ #include <mbgl/style/light.hpp> #include <mbgl/style/light_impl.hpp> -#include <mbgl/style/light_properties.hpp> +#include <mbgl/style/light_observer.hpp> namespace mbgl { namespace style { +static LightObserver nullObserver; + Light::Light() - : impl(std::make_unique<Impl>()) { + : impl(makeMutable<Impl>()), + observer(&nullObserver) { } Light::~Light() = default; +void Light::setObserver(LightObserver* observer_) { + observer = observer_ ? observer_ : &nullObserver; +} + +Mutable<Light::Impl> Light::mutableImpl() const { + return makeMutable<Impl>(*impl); +} + LightAnchorType Light::getDefaultAnchor() { return LightAnchor::defaultValue(); } @@ -22,17 +33,21 @@ PropertyValue<LightAnchorType> Light::getAnchor() const { } void Light::setAnchor(PropertyValue<LightAnchorType> property) { - impl->properties.template get<LightAnchor>().value = property; - impl->observer->onLightChanged(*this); + auto impl_ = mutableImpl(); + impl_->properties.template get<LightAnchor>().value = property; + impl = std::move(impl_); + observer->onLightChanged(*this); } -void Light::setAnchorTransition(const TransitionOptions& transition) { - impl->properties.template get<LightAnchor>().transition = transition; - impl->observer->onLightChanged(*this); +void Light::setAnchorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->properties.template get<LightAnchor>().options = options; + impl = std::move(impl_); + observer->onLightChanged(*this); } TransitionOptions Light::getAnchorTransition() const { - return impl->properties.template get<LightAnchor>().transition; + return impl->properties.template get<LightAnchor>().options; } Position Light::getDefaultPosition() { @@ -44,17 +59,21 @@ PropertyValue<Position> Light::getPosition() const { } void Light::setPosition(PropertyValue<Position> property) { - impl->properties.template get<LightPosition>().value = property; - impl->observer->onLightChanged(*this); + auto impl_ = mutableImpl(); + impl_->properties.template get<LightPosition>().value = property; + impl = std::move(impl_); + observer->onLightChanged(*this); } -void Light::setPositionTransition(const TransitionOptions& transition) { - impl->properties.template get<LightPosition>().transition = transition; - impl->observer->onLightChanged(*this); +void Light::setPositionTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->properties.template get<LightPosition>().options = options; + impl = std::move(impl_); + observer->onLightChanged(*this); } TransitionOptions Light::getPositionTransition() const { - return impl->properties.template get<LightPosition>().transition; + return impl->properties.template get<LightPosition>().options; } Color Light::getDefaultColor() { @@ -66,17 +85,21 @@ PropertyValue<Color> Light::getColor() const { } void Light::setColor(PropertyValue<Color> property) { - impl->properties.template get<LightColor>().value = property; - impl->observer->onLightChanged(*this); + auto impl_ = mutableImpl(); + impl_->properties.template get<LightColor>().value = property; + impl = std::move(impl_); + observer->onLightChanged(*this); } -void Light::setColorTransition(const TransitionOptions& transition) { - impl->properties.template get<LightColor>().transition = transition; - impl->observer->onLightChanged(*this); +void Light::setColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->properties.template get<LightColor>().options = options; + impl = std::move(impl_); + observer->onLightChanged(*this); } TransitionOptions Light::getColorTransition() const { - return impl->properties.template get<LightColor>().transition; + return impl->properties.template get<LightColor>().options; } float Light::getDefaultIntensity() { @@ -88,17 +111,21 @@ PropertyValue<float> Light::getIntensity() const { } void Light::setIntensity(PropertyValue<float> property) { - impl->properties.template get<LightIntensity>().value = property; - impl->observer->onLightChanged(*this); + auto impl_ = mutableImpl(); + impl_->properties.template get<LightIntensity>().value = property; + impl = std::move(impl_); + observer->onLightChanged(*this); } -void Light::setIntensityTransition(const TransitionOptions& transition) { - impl->properties.template get<LightIntensity>().transition = transition; - impl->observer->onLightChanged(*this); +void Light::setIntensityTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->properties.template get<LightIntensity>().options = options; + impl = std::move(impl_); + observer->onLightChanged(*this); } TransitionOptions Light::getIntensityTransition() const { - return impl->properties.template get<LightIntensity>().transition; + return impl->properties.template get<LightIntensity>().options; } diff --git a/src/mbgl/style/light.cpp.ejs b/src/mbgl/style/light.cpp.ejs index c82c65c10c..45241c60fd 100644 --- a/src/mbgl/style/light.cpp.ejs +++ b/src/mbgl/style/light.cpp.ejs @@ -5,17 +5,28 @@ #include <mbgl/style/light.hpp> #include <mbgl/style/light_impl.hpp> -#include <mbgl/style/light_properties.hpp> +#include <mbgl/style/light_observer.hpp> namespace mbgl { namespace style { +static LightObserver nullObserver; + Light::Light() - : impl(std::make_unique<Impl>()) { + : impl(makeMutable<Impl>()), + observer(&nullObserver) { } Light::~Light() = default; +void Light::setObserver(LightObserver* observer_) { + observer = observer_ ? observer_ : &nullObserver; +} + +Mutable<Light::Impl> Light::mutableImpl() const { + return makeMutable<Impl>(*impl); +} + <% for (const property of properties) { -%> <%- evaluatedType(property) %> Light::getDefault<%- camelize(property.name) %>() { return Light<%- camelize(property.name) %>::defaultValue(); @@ -26,17 +37,21 @@ Light::~Light() = default; } void Light::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> property) { - impl->properties.template get<Light<%- camelize(property.name) %>>().value = property; - impl->observer->onLightChanged(*this); + auto impl_ = mutableImpl(); + impl_->properties.template get<Light<%- camelize(property.name) %>>().value = property; + impl = std::move(impl_); + observer->onLightChanged(*this); } -void Light::set<%- camelize(property.name) %>Transition(const TransitionOptions& transition) { - impl->properties.template get<Light<%- camelize(property.name) %>>().transition = transition; - impl->observer->onLightChanged(*this); +void Light::set<%- camelize(property.name) %>Transition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->properties.template get<Light<%- camelize(property.name) %>>().options = options; + impl = std::move(impl_); + observer->onLightChanged(*this); } TransitionOptions Light::get<%- camelize(property.name) %>Transition() const { - return impl->properties.template get<Light<%- camelize(property.name) %>>().transition; + return impl->properties.template get<Light<%- camelize(property.name) %>>().options; } <% } -%> diff --git a/src/mbgl/style/light_impl.cpp b/src/mbgl/style/light_impl.cpp index e0ab1176ed..619d115f02 100644 --- a/src/mbgl/style/light_impl.cpp +++ b/src/mbgl/style/light_impl.cpp @@ -3,9 +3,5 @@ namespace mbgl { namespace style { -void Light::Impl::setObserver(LightObserver* observer_) { - observer = observer_; -} - } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/light_impl.hpp b/src/mbgl/style/light_impl.hpp index b4fd886742..f094c9d462 100644 --- a/src/mbgl/style/light_impl.hpp +++ b/src/mbgl/style/light_impl.hpp @@ -1,19 +1,58 @@ #pragma once -#include <mbgl/style/light_properties.hpp> -#include <mbgl/style/light_observer.hpp> +#include <mbgl/style/light.hpp> +#include <mbgl/style/property_value.hpp> +#include <mbgl/style/types.hpp> +#include <mbgl/style/position.hpp> +#include <mbgl/style/properties.hpp> +#include <mbgl/renderer/property_evaluator.hpp> +#include <mbgl/util/color.hpp> +#include <mbgl/util/indexed_tuple.hpp> namespace mbgl { namespace style { -class Light::Impl { +template <class T> +class LightProperty { public: + using TransitionableType = Transitionable<PropertyValue<T>>; + using UnevaluatedType = Transitioning<PropertyValue<T>>; + using EvaluatorType = PropertyEvaluator<T>; + using PossiblyEvaluatedType = T; + using Type = T; + static constexpr bool IsDataDriven = false; +}; + +struct LightAnchor : LightProperty<LightAnchorType> { + static LightAnchorType defaultValue() { + return LightAnchorType::Viewport; + } +}; + +struct LightPosition : LightProperty<Position> { + static Position defaultValue() { + std::array<float, 3> default_ = { { 1.15, 210, 30 } }; + return Position{ { default_ } }; + } +}; - LightObserver nullObserver; - LightObserver* observer = &nullObserver; - void setObserver(LightObserver*); +struct LightColor : LightProperty<Color> { + static Color defaultValue() { + return Color::white(); + } +}; + +struct LightIntensity : LightProperty<float> { + static float defaultValue() { + return 0.5; + } +}; - IndexedTuple<LightProperties, LightProperties> properties; +using LightProperties = Properties<LightAnchor, LightPosition, LightColor, LightIntensity>; + +class Light::Impl { +public: + LightProperties::Transitionable properties; }; } // namespace style diff --git a/src/mbgl/style/light_observer.hpp b/src/mbgl/style/light_observer.hpp index 751a84850d..45beb64928 100644 --- a/src/mbgl/style/light_observer.hpp +++ b/src/mbgl/style/light_observer.hpp @@ -1,10 +1,10 @@ #pragma once -#include <mbgl/style/light.hpp> - namespace mbgl { namespace style { +class Light; + class LightObserver { public: virtual ~LightObserver() = default; diff --git a/src/mbgl/style/light_properties.hpp b/src/mbgl/style/light_properties.hpp deleted file mode 100644 index 9f6088a633..0000000000 --- a/src/mbgl/style/light_properties.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include <mbgl/style/property_value.hpp> -#include <mbgl/style/transition_options.hpp> -#include <mbgl/style/types.hpp> -#include <mbgl/style/position.hpp> -#include <mbgl/util/color.hpp> -#include <mbgl/util/indexed_tuple.hpp> - -namespace mbgl { -namespace style { - -template <class T> -class LightProperty { -public: - using Type = T; - using ValueType = PropertyValue<T>; - - PropertyValue<T> value; - TransitionOptions transition; -}; - -struct LightAnchor : LightProperty<LightAnchorType> { - static LightAnchorType defaultValue() { - return LightAnchorType::Viewport; - } -}; - -struct LightPosition : LightProperty<Position> { - static Position defaultValue() { - std::array<float, 3> default_ = { { 1.15, 210, 30 } }; - return Position{ { default_ } }; - } -}; - -struct LightColor : LightProperty<Color> { - static Color defaultValue() { - return Color::white(); - } -}; - -struct LightIntensity : LightProperty<float> { - static float defaultValue() { - return 0.5; - } -}; - -using LightProperties = TypeList<LightAnchor, LightPosition, LightColor, LightIntensity>; - -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/observer.hpp b/src/mbgl/style/observer.hpp index 60432334e2..cc6378b366 100644 --- a/src/mbgl/style/observer.hpp +++ b/src/mbgl/style/observer.hpp @@ -1,22 +1,18 @@ #pragma once -#include <mbgl/text/glyph_atlas_observer.hpp> -#include <mbgl/sprite/sprite_atlas_observer.hpp> #include <mbgl/style/source_observer.hpp> -#include <mbgl/map/update.hpp> #include <exception> namespace mbgl { namespace style { -class Observer : public GlyphAtlasObserver, - public SpriteAtlasObserver, - public SourceObserver { +class Observer : public SourceObserver { public: - virtual void onUpdate(Update) {} - virtual void onStyleError(std::exception_ptr) {} + virtual void onStyleLoading() {} virtual void onStyleLoaded() {} + virtual void onUpdate() {} + virtual void onStyleError(std::exception_ptr) {} virtual void onResourceError(std::exception_ptr) {} }; diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp index c203083c49..c4c996b3bd 100644 --- a/src/mbgl/style/paint_property.hpp +++ b/src/mbgl/style/paint_property.hpp @@ -1,108 +1,38 @@ #pragma once -#include <mbgl/style/class_dictionary.hpp> +#include <mbgl/style/properties.hpp> #include <mbgl/style/property_value.hpp> #include <mbgl/style/data_driven_property_value.hpp> -#include <mbgl/style/transition_options.hpp> #include <mbgl/renderer/property_evaluator.hpp> #include <mbgl/renderer/cross_faded_property_evaluator.hpp> #include <mbgl/renderer/data_driven_property_evaluator.hpp> -#include <mbgl/renderer/property_evaluation_parameters.hpp> -#include <mbgl/renderer/cascade_parameters.hpp> -#include <mbgl/renderer/transitioning_property.hpp> -#include <mbgl/renderer/paint_property_binder.hpp> -#include <mbgl/util/constants.hpp> -#include <mbgl/util/interpolate.hpp> -#include <mbgl/util/indexed_tuple.hpp> -#include <mbgl/util/ignore.hpp> #include <utility> namespace mbgl { - -class GeometryTileFeature; - namespace style { -template <class Value> -class CascadingPaintProperty { -public: - bool isUndefined() const { - return values.find(ClassID::Default) == values.end(); - } - - const Value& get(const optional<std::string>& klass) const { - static const Value staticValue{}; - const auto it = values.find(klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default); - return it == values.end() ? staticValue : it->second; - } - - void set(const Value& value_, const optional<std::string>& klass) { - values[klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default] = value_; - } - - const TransitionOptions& getTransition(const optional<std::string>& klass) const { - static const TransitionOptions staticValue{}; - const auto it = transitions.find(klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default); - return it == transitions.end() ? staticValue : it->second; - } - - void setTransition(const TransitionOptions& transition, const optional<std::string>& klass) { - transitions[klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default] = transition; - } - - template <class TransitioningProperty> - TransitioningProperty cascade(const CascadeParameters& params, TransitioningProperty prior) const { - TransitionOptions transition; - Value value; - - for (const auto classID : params.classes) { - if (values.find(classID) != values.end()) { - value = values.at(classID); - break; - } - } - - for (const auto classID : params.classes) { - if (transitions.find(classID) != transitions.end()) { - transition = transitions.at(classID).reverseMerge(transition); - break; - } - } - - return TransitioningProperty(std::move(value), - std::move(prior), - transition.reverseMerge(params.transition), - params.now); - } - -private: - std::map<ClassID, Value> values; - std::map<ClassID, TransitionOptions> transitions; -}; - template <class T> class PaintProperty { public: - using ValueType = PropertyValue<T>; - using CascadingType = CascadingPaintProperty<ValueType>; - using UnevaluatedType = TransitioningProperty<ValueType>; + using TransitionableType = Transitionable<PropertyValue<T>>; + using UnevaluatedType = Transitioning<PropertyValue<T>>; using EvaluatorType = PropertyEvaluator<T>; - using EvaluatedType = T; + using PossiblyEvaluatedType = T; + using Type = T; static constexpr bool IsDataDriven = false; }; template <class T, class A, class U> class DataDrivenPaintProperty { public: - using ValueType = DataDrivenPropertyValue<T>; - using CascadingType = CascadingPaintProperty<ValueType>; - using UnevaluatedType = TransitioningProperty<ValueType>; + using TransitionableType = Transitionable<DataDrivenPropertyValue<T>>; + using UnevaluatedType = Transitioning<DataDrivenPropertyValue<T>>; using EvaluatorType = DataDrivenPropertyEvaluator<T>; - using EvaluatedType = PossiblyEvaluatedPropertyValue<T>; + using PossiblyEvaluatedType = PossiblyEvaluatedPropertyValue<T>; + using Type = T; static constexpr bool IsDataDriven = true; - using Type = T; using Attribute = A; using Uniform = U; }; @@ -110,78 +40,13 @@ public: template <class T> class CrossFadedPaintProperty { public: - using ValueType = PropertyValue<T>; - using CascadingType = CascadingPaintProperty<ValueType>; - using UnevaluatedType = TransitioningProperty<ValueType>; + using TransitionableType = Transitionable<PropertyValue<T>>; + using UnevaluatedType = Transitioning<PropertyValue<T>>; using EvaluatorType = CrossFadedPropertyEvaluator<T>; - using EvaluatedType = Faded<T>; + using PossiblyEvaluatedType = Faded<T>; + using Type = T; static constexpr bool IsDataDriven = false; }; -template <class P> -struct IsDataDriven : std::integral_constant<bool, P::IsDataDriven> {}; - -template <class... Ps> -class PaintProperties { -public: - using Properties = TypeList<Ps...>; - using DataDrivenProperties = FilteredTypeList<Properties, IsDataDriven>; - using Binders = PaintPropertyBinders<DataDrivenProperties>; - - using EvaluatedTypes = TypeList<typename Ps::EvaluatedType...>; - using UnevaluatedTypes = TypeList<typename Ps::UnevaluatedType...>; - using CascadingTypes = TypeList<typename Ps::CascadingType...>; - - template <class TypeList> - using Tuple = IndexedTuple<Properties, TypeList>; - - class Evaluated : public Tuple<EvaluatedTypes> { - public: - using Tuple<EvaluatedTypes>::Tuple; - }; - - class Unevaluated : public Tuple<UnevaluatedTypes> { - public: - using Tuple<UnevaluatedTypes>::Tuple; - - bool hasTransition() const { - bool result = false; - util::ignore({ result |= this->template get<Ps>().hasTransition()... }); - return result; - } - - template <class P> - auto evaluate(const PropertyEvaluationParameters& parameters) { - using Evaluator = typename P::EvaluatorType; - - return this->template get<P>().evaluate( - Evaluator(parameters, P::defaultValue()), - parameters.now - ); - } - - Evaluated evaluate(const PropertyEvaluationParameters& parameters) { - return Evaluated { - evaluate<Ps>(parameters)... - }; - } - - }; - - class Cascading : public Tuple<CascadingTypes> { - public: - using Tuple<CascadingTypes>::Tuple; - - Unevaluated cascade(const CascadeParameters& parameters, Unevaluated&& prior) const { - return Unevaluated { - this->template get<Ps>().cascade( - parameters, - std::move(prior.template get<Ps>()) - )... - }; - } - }; -}; - } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp index fc3ccf410b..a83897dbf5 100644 --- a/src/mbgl/style/parser.cpp +++ b/src/mbgl/style/parser.cpp @@ -2,11 +2,13 @@ #include <mbgl/style/layer_impl.hpp> #include <mbgl/style/rapidjson_conversion.hpp> #include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/coordinate.hpp> #include <mbgl/style/conversion/source.hpp> #include <mbgl/style/conversion/layer.hpp> #include <mbgl/style/conversion/light.hpp> #include <mbgl/util/logging.hpp> +#include <mbgl/util/string.hpp> #include <mapbox/geojsonvt.hpp> @@ -55,10 +57,12 @@ StyleParseResult Parser::parse(const std::string& json) { if (document.HasMember("center")) { const JSValue& value = document["center"]; - if (value.IsArray() && value.Size() >= 2) { - // Style spec uses lon/lat order - latLng = LatLng(value[1].IsNumber() ? value[1].GetDouble() : 0, - value[0].IsNumber() ? value[0].GetDouble() : 0); + conversion::Error error; + auto convertedLatLng = conversion::convert<LatLng>(value, error); + if (convertedLatLng) { + latLng = *convertedLatLng; + } else { + Log::Warning(Event::ParseStyle, "center coordinate must be a longitude, latitude pair"); } } @@ -83,6 +87,10 @@ StyleParseResult Parser::parse(const std::string& json) { } } + if (document.HasMember("transition")) { + parseTransition(document["transition"]); + } + if (document.HasMember("light")) { parseLight(document["light"]); } @@ -112,6 +120,17 @@ StyleParseResult Parser::parse(const std::string& json) { return nullptr; } +void Parser::parseTransition(const JSValue& value) { + conversion::Error error; + optional<TransitionOptions> converted = conversion::convert<TransitionOptions>(value, error); + if (!converted) { + Log::Warning(Event::ParseStyle, error.message); + return; + } + + transition = std::move(*converted); +} + void Parser::parseLight(const JSValue& value) { conversion::Error error; optional<Light> converted = conversion::convert<Light>(value, error); @@ -236,7 +255,7 @@ void Parser::parseLayer(const std::string& id, const JSValue& value, std::unique return; } - layer = reference->baseImpl->cloneRef(id); + layer = reference->cloneRef(id); conversion::setPaintProperties(*layer, value); } else { conversion::Error error; diff --git a/src/mbgl/style/parser.hpp b/src/mbgl/style/parser.hpp index 32b8a7a8bc..401b5ff513 100644 --- a/src/mbgl/style/parser.hpp +++ b/src/mbgl/style/parser.hpp @@ -32,6 +32,7 @@ public: std::vector<std::unique_ptr<Source>> sources; std::vector<std::unique_ptr<Layer>> layers; + TransitionOptions transition; Light light; std::string name; @@ -44,6 +45,7 @@ public: std::vector<FontStack> fontStacks() const; private: + void parseTransition(const JSValue&); void parseLight(const JSValue&); void parseSources(const JSValue&); void parseLayers(const JSValue&); diff --git a/src/mbgl/style/properties.hpp b/src/mbgl/style/properties.hpp new file mode 100644 index 0000000000..dfcf7993a7 --- /dev/null +++ b/src/mbgl/style/properties.hpp @@ -0,0 +1,248 @@ +#pragma once + +#include <mbgl/style/transition_options.hpp> +#include <mbgl/style/conversion/stringify.hpp> +#include <mbgl/renderer/transition_parameters.hpp> +#include <mbgl/renderer/paint_property_binder.hpp> +#include <mbgl/renderer/property_evaluation_parameters.hpp> +#include <mbgl/renderer/transition_parameters.hpp> +#include <mbgl/util/indexed_tuple.hpp> +#include <mbgl/util/ignore.hpp> + +namespace mbgl { + +class GeometryTileFeature; + +namespace style { + +template <class Value> +class Transitioning { +public: + Transitioning() = default; + + explicit Transitioning(Value value_) + : value(std::move(value_)) { + } + + Transitioning(Value value_, + Transitioning<Value> prior_, + TransitionOptions transition, + TimePoint now) + : begin(now + transition.delay.value_or(Duration::zero())), + end(begin + transition.duration.value_or(Duration::zero())), + value(std::move(value_)) { + if (transition.isDefined()) { + prior = { std::move(prior_) }; + } + } + + template <class Evaluator> + auto evaluate(const Evaluator& evaluator, TimePoint now) const { + auto finalValue = value.evaluate(evaluator); + if (!prior) { + // No prior value. + return finalValue; + } else if (now >= end) { + // Transition from prior value is now complete. + prior = {}; + return finalValue; + } else if (value.isDataDriven()) { + // Transitions to data-driven properties are not supported. + // We snap immediately to the data-driven value so that, when we perform layout, + // we see the data-driven function and can use it to populate vertex buffers. + prior = {}; + return finalValue; + } else if (now < begin) { + // Transition hasn't started yet. + return prior->get().evaluate(evaluator, now); + } else { + // Interpolate between recursively-calculated prior value and final. + float t = std::chrono::duration<float>(now - begin) / (end - begin); + return util::interpolate(prior->get().evaluate(evaluator, now), finalValue, + util::DEFAULT_TRANSITION_EASE.solve(t, 0.001)); + } + } + + bool hasTransition() const { + return bool(prior); + } + + bool isUndefined() const { + return value.isUndefined(); + } + + const Value& getValue() const { + return value; + } + +private: + mutable optional<mapbox::util::recursive_wrapper<Transitioning<Value>>> prior; + TimePoint begin; + TimePoint end; + Value value; +}; + +template <class Value> +class Transitionable { +public: + Value value; + TransitionOptions options; + + Transitioning<Value> transition(const TransitionParameters& params, Transitioning<Value> prior) const { + return Transitioning<Value>(value, + std::move(prior), + options.reverseMerge(params.transition), + params.now); + } +}; + +template <class P> +struct IsDataDriven : std::integral_constant<bool, P::IsDataDriven> {}; + +template <class... Ps> +class Properties { +public: + /* + For style properties we implement a two step evaluation process: if you have a zoom level, + you can evaluate a set of unevaluated property values, producing a set of possibly evaluated + values, where undefined, constant, or camera function values have been fully evaluated, and + source or composite function values have not. + + Once you also have a particular feature, you can evaluate that set of possibly evaluated values + fully, producing a set of fully evaluated values. + + This is in theory maximally efficient in terms of avoiding repeated evaluation of camera + functions, though it's more of a historical accident than a purposeful optimization. + */ + + using PropertyTypes = TypeList<Ps...>; + using TransitionableTypes = TypeList<typename Ps::TransitionableType...>; + using UnevaluatedTypes = TypeList<typename Ps::UnevaluatedType...>; + using PossiblyEvaluatedTypes = TypeList<typename Ps::PossiblyEvaluatedType...>; + using EvaluatedTypes = TypeList<typename Ps::Type...>; + + using DataDrivenProperties = FilteredTypeList<PropertyTypes, IsDataDriven>; + using Binders = PaintPropertyBinders<DataDrivenProperties>; + + template <class TypeList> + using Tuple = IndexedTuple<PropertyTypes, TypeList>; + + class Evaluated : public Tuple<EvaluatedTypes> { + public: + template <class... Us> + Evaluated(Us&&... us) + : Tuple<EvaluatedTypes>(std::forward<Us>(us)...) { + } + }; + + class PossiblyEvaluated : public Tuple<PossiblyEvaluatedTypes> { + public: + template <class... Us> + PossiblyEvaluated(Us&&... us) + : Tuple<PossiblyEvaluatedTypes>(std::forward<Us>(us)...) { + } + + template <class T> + static T evaluate(float, const GeometryTileFeature&, const T& t, const T&) { + return t; + } + + template <class T> + static T evaluate(float z, const GeometryTileFeature& feature, + const PossiblyEvaluatedPropertyValue<T>& v, const T& defaultValue) { + return v.match( + [&] (const T& t) { + return t; + }, + [&] (const SourceFunction<T>& t) { + return t.evaluate(feature, defaultValue); + }, + [&] (const CompositeFunction<T>& t) { + return t.evaluate(z, feature, defaultValue); + }); + } + + template <class P> + auto evaluate(float z, const GeometryTileFeature& feature) const { + return evaluate(z, feature, this->template get<P>(), P::defaultValue()); + } + + Evaluated evaluate(float z, const GeometryTileFeature& feature) const { + return Evaluated { + evaluate<Ps>(z, feature)... + }; + } + }; + + class Unevaluated : public Tuple<UnevaluatedTypes> { + public: + template <class... Us> + Unevaluated(Us&&... us) + : Tuple<UnevaluatedTypes>(std::forward<Us>(us)...) { + } + + bool hasTransition() const { + bool result = false; + util::ignore({ result |= this->template get<Ps>().hasTransition()... }); + return result; + } + + template <class P> + auto evaluate(const PropertyEvaluationParameters& parameters) const { + using Evaluator = typename P::EvaluatorType; + return this->template get<P>() + .evaluate(Evaluator(parameters, P::defaultValue()), parameters.now); + } + + PossiblyEvaluated evaluate(const PropertyEvaluationParameters& parameters) const { + return PossiblyEvaluated { + evaluate<Ps>(parameters)... + }; + } + + template <class Writer> + void stringify(Writer& writer) const { + writer.StartObject(); + util::ignore({ (conversion::stringify<Ps>(writer, this->template get<Ps>()), 0)... }); + writer.EndObject(); + } + }; + + class Transitionable : public Tuple<TransitionableTypes> { + public: + template <class... Us> + Transitionable(Us&&... us) + : Tuple<TransitionableTypes>(std::forward<Us>(us)...) { + } + + Unevaluated transitioned(const TransitionParameters& parameters, Unevaluated&& prior) const { + return Unevaluated { + this->template get<Ps>() + .transition(parameters, std::move(prior.template get<Ps>()))... + }; + } + + Unevaluated untransitioned() const { + return Unevaluated { + typename Ps::UnevaluatedType(this->template get<Ps>().value)... + }; + } + + bool hasDataDrivenPropertyDifference(const Transitionable& other) const { + bool result = false; + util::ignore({ (result |= this->template get<Ps>().value.hasDataDrivenPropertyDifference(other.template get<Ps>().value))... }); + return result; + } + }; +}; + +template <class...> +struct ConcatenateProperties; + +template <class... As, class... Bs> +struct ConcatenateProperties<TypeList<As...>, TypeList<Bs...>> { + using Type = Properties<As..., Bs...>; +}; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/rapidjson_conversion.hpp b/src/mbgl/style/rapidjson_conversion.hpp index 101fe67ec0..48a764ccb4 100644 --- a/src/mbgl/style/rapidjson_conversion.hpp +++ b/src/mbgl/style/rapidjson_conversion.hpp @@ -62,6 +62,13 @@ inline optional<float> toNumber(const JSValue& value) { return value.GetDouble(); } +inline optional<double> toDouble(const JSValue& value) { + if (!value.IsNumber()) { + return {}; + } + return value.GetDouble(); +} + inline optional<std::string> toString(const JSValue& value) { if (!value.IsString()) { return {}; diff --git a/src/mbgl/style/source.cpp b/src/mbgl/style/source.cpp index cfb268006b..e7701b8bec 100644 --- a/src/mbgl/style/source.cpp +++ b/src/mbgl/style/source.cpp @@ -1,16 +1,25 @@ #include <mbgl/style/source.hpp> #include <mbgl/style/source_impl.hpp> +#include <mbgl/style/source_observer.hpp> +#include <mbgl/util/logging.hpp> namespace mbgl { namespace style { -Source::Source(SourceType type_, std::unique_ptr<Impl> baseImpl_) - : baseImpl(std::move(baseImpl_)), type(type_) { +static SourceObserver nullObserver; + +Source::Source(Immutable<Impl> impl) + : baseImpl(std::move(impl)), + observer(&nullObserver) { } Source::~Source() = default; -const std::string& Source::getID() const { +SourceType Source::getType() const { + return baseImpl->type; +} + +std::string Source::getID() const { return baseImpl->id; } @@ -18,5 +27,14 @@ optional<std::string> Source::getAttribution() const { return baseImpl->getAttribution(); } +void Source::setObserver(SourceObserver* observer_) { + observer = observer_ ? observer_ : &nullObserver; +} + +void Source::dumpDebugLogs() const { + Log::Info(Event::General, "Source::id: %s", getID().c_str()); + Log::Info(Event::General, "Source::loaded: %d", loaded); +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/source_impl.cpp b/src/mbgl/style/source_impl.cpp index 1e9405abbb..0683f847cb 100644 --- a/src/mbgl/style/source_impl.cpp +++ b/src/mbgl/style/source_impl.cpp @@ -1,26 +1,11 @@ #include <mbgl/style/source_impl.hpp> -#include <mbgl/style/source_observer.hpp> -#include <mbgl/util/logging.hpp> namespace mbgl { namespace style { -static SourceObserver nullObserver; - -Source::Impl::Impl(SourceType type_, std::string id_, Source& base_) +Source::Impl::Impl(SourceType type_, std::string id_) : type(type_), - id(std::move(id_)), - base(base_), - observer(&nullObserver) { -} - -void Source::Impl::dumpDebugLogs() const { - Log::Info(Event::General, "Source::id: %s", base.getID().c_str()); - Log::Info(Event::General, "Source::loaded: %d", loaded); -} - -void Source::Impl::setObserver(SourceObserver* observer_) { - observer = observer_ ? observer_ : &nullObserver; + id(std::move(id_)) { } } // namespace style diff --git a/src/mbgl/style/source_impl.hpp b/src/mbgl/style/source_impl.hpp index 2514ec5120..42da97345a 100644 --- a/src/mbgl/style/source_impl.hpp +++ b/src/mbgl/style/source_impl.hpp @@ -3,35 +3,30 @@ #include <mbgl/style/source.hpp> #include <mbgl/util/noncopyable.hpp> +#include <string> + namespace mbgl { -class FileSource; class RenderSource; namespace style { class SourceObserver; -class Source::Impl : private util::noncopyable { +class Source::Impl { public: - Impl(SourceType, std::string id, Source&); virtual ~Impl() = default; - virtual void loadDescription(FileSource&) = 0; - virtual std::unique_ptr<RenderSource> createRenderSource() const = 0; + Impl& operator=(const Impl&) = delete; - virtual optional<std::string> getAttribution() const { return {}; }; + virtual optional<std::string> getAttribution() const = 0; const SourceType type; const std::string id; - bool loaded = false; - Source& base; - - void setObserver(SourceObserver*); - SourceObserver* observer = nullptr; - - void dumpDebugLogs() const; +protected: + Impl(SourceType, std::string); + Impl(const Impl&) = default; }; } // namespace style diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp index 992f82b1e7..4e3478322d 100644 --- a/src/mbgl/style/sources/geojson_source.cpp +++ b/src/mbgl/style/sources/geojson_source.cpp @@ -1,27 +1,81 @@ #include <mbgl/style/sources/geojson_source.hpp> #include <mbgl/style/sources/geojson_source_impl.hpp> #include <mbgl/style/source_observer.hpp> +#include <mbgl/style/conversion/json.hpp> +#include <mbgl/style/conversion/geojson.hpp> +#include <mbgl/storage/file_source.hpp> +#include <mbgl/util/logging.hpp> namespace mbgl { namespace style { GeoJSONSource::GeoJSONSource(const std::string& id, const GeoJSONOptions& options) - : Source(SourceType::GeoJSON, - std::make_unique<GeoJSONSource::Impl>(std::move(id), *this, options)), - impl(static_cast<Impl*>(baseImpl.get())) { + : Source(makeMutable<Impl>(std::move(id), options)) { } -void GeoJSONSource::setURL(const std::string& url) { - impl->setURL(url); +GeoJSONSource::~GeoJSONSource() = default; + +const GeoJSONSource::Impl& GeoJSONSource::impl() const { + return static_cast<const Impl&>(*baseImpl); +} + +void GeoJSONSource::setURL(const std::string& url_) { + url = std::move(url_); + + // Signal that the source description needs a reload + if (loaded || req) { + loaded = false; + req.reset(); + observer->onSourceDescriptionChanged(*this); + } } void GeoJSONSource::setGeoJSON(const mapbox::geojson::geojson& geoJSON) { - impl->setGeoJSON(geoJSON); - impl->observer->onSourceChanged(*this); + req.reset(); + baseImpl = makeMutable<Impl>(impl(), geoJSON); + observer->onSourceChanged(*this); } optional<std::string> GeoJSONSource::getURL() const { - return impl->getURL(); + return url; +} + +void GeoJSONSource::loadDescription(FileSource& fileSource) { + if (!url) { + loaded = true; + return; + } + + if (req) { + return; + } + + req = fileSource.request(Resource::source(*url), [this](Response res) { + if (res.error) { + observer->onSourceError( + *this, std::make_exception_ptr(std::runtime_error(res.error->message))); + } else if (res.notModified) { + return; + } else if (res.noContent) { + observer->onSourceError( + *this, std::make_exception_ptr(std::runtime_error("unexpectedly empty GeoJSON"))); + } else { + conversion::Error error; + optional<GeoJSON> geoJSON = conversion::convertJSON<GeoJSON>(*res.data, error); + if (!geoJSON) { + Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s", + error.message.c_str()); + // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for + // tiles to load. + baseImpl = makeMutable<Impl>(impl(), GeoJSON{ FeatureCollection{} }); + } else { + baseImpl = makeMutable<Impl>(impl(), *geoJSON); + } + + loaded = true; + observer->onSourceLoaded(*this); + } + }); } } // namespace style diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp index 1a686ff9bc..efa4018b46 100644 --- a/src/mbgl/style/sources/geojson_source_impl.cpp +++ b/src/mbgl/style/sources/geojson_source_impl.cpp @@ -1,16 +1,13 @@ #include <mbgl/style/sources/geojson_source_impl.hpp> -#include <mbgl/style/conversion/json.hpp> -#include <mbgl/style/conversion/geojson.hpp> -#include <mbgl/style/source_observer.hpp> +#include <mbgl/util/constants.hpp> #include <mbgl/tile/tile_id.hpp> -#include <mbgl/storage/file_source.hpp> -#include <mbgl/renderer/sources/render_geojson_source.hpp> -#include <mbgl/util/constants.cpp> -#include <mbgl/util/logging.hpp> +#include <mbgl/util/string.hpp> #include <mapbox/geojsonvt.hpp> #include <supercluster.hpp> +#include <cmath> + namespace mbgl { namespace style { @@ -42,33 +39,14 @@ private: mapbox::supercluster::Supercluster impl; }; -GeoJSONSource::Impl::Impl(std::string id_, Source& base_, const GeoJSONOptions options_) - : Source::Impl(SourceType::GeoJSON, std::move(id_), base_), options(options_) { -} - -GeoJSONSource::Impl::~Impl() = default; - -void GeoJSONSource::Impl::setURL(std::string url_) { - url = std::move(url_); - - // Signal that the source description needs a reload - if (loaded || req) { - loaded = false; - req.reset(); - observer->onSourceDescriptionChanged(base); - } -} - -optional<std::string> GeoJSONSource::Impl::getURL() const { - return url; -} - -void GeoJSONSource::Impl::setGeoJSON(const GeoJSON& geoJSON) { - req.reset(); - _setGeoJSON(geoJSON); +GeoJSONSource::Impl::Impl(std::string id_, GeoJSONOptions options_) + : Source::Impl(SourceType::GeoJSON, std::move(id_)), + options(std::move(options_)) { } -void GeoJSONSource::Impl::_setGeoJSON(const GeoJSON& geoJSON) { +GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON) + : Source::Impl(other), + options(other.options) { double scale = util::EXTENT / util::tileSize; if (options.cluster @@ -77,60 +55,20 @@ void GeoJSONSource::Impl::_setGeoJSON(const GeoJSON& geoJSON) { mapbox::supercluster::Options clusterOptions; clusterOptions.maxZoom = options.clusterMaxZoom; clusterOptions.extent = util::EXTENT; - clusterOptions.radius = std::round(scale * options.clusterRadius); + clusterOptions.radius = ::round(scale * options.clusterRadius); data = std::make_unique<SuperclusterData>( geoJSON.get<mapbox::geometry::feature_collection<double>>(), clusterOptions); } else { mapbox::geojsonvt::Options vtOptions; vtOptions.maxZoom = options.maxzoom; vtOptions.extent = util::EXTENT; - vtOptions.buffer = std::round(scale * options.buffer); + vtOptions.buffer = ::round(scale * options.buffer); vtOptions.tolerance = scale * options.tolerance; data = std::make_unique<GeoJSONVTData>(geoJSON, vtOptions); } } -void GeoJSONSource::Impl::loadDescription(FileSource& fileSource) { - if (!url) { - loaded = true; - return; - } - - if (req) { - return; - } - - req = fileSource.request(Resource::source(*url), [this](Response res) { - if (res.error) { - observer->onSourceError( - base, std::make_exception_ptr(std::runtime_error(res.error->message))); - } else if (res.notModified) { - return; - } else if (res.noContent) { - observer->onSourceError( - base, std::make_exception_ptr(std::runtime_error("unexpectedly empty GeoJSON"))); - } else { - conversion::Error error; - optional<GeoJSON> geoJSON = conversion::convertJSON<GeoJSON>(*res.data, error); - if (!geoJSON) { - Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s", - error.message.c_str()); - // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for - // tiles to load. - _setGeoJSON(GeoJSON{ FeatureCollection{} }); - } else { - _setGeoJSON(*geoJSON); - } - - loaded = true; - observer->onSourceLoaded(base); - } - }); -} - -std::unique_ptr<RenderSource> GeoJSONSource::Impl::createRenderSource() const { - return std::make_unique<RenderGeoJSONSource>(*this); -} +GeoJSONSource::Impl::~Impl() = default; Range<uint8_t> GeoJSONSource::Impl::getZoomRange() const { return { 0, options.maxzoom }; @@ -140,5 +78,9 @@ GeoJSONData* GeoJSONSource::Impl::getData() const { return data.get(); } +optional<std::string> GeoJSONSource::Impl::getAttribution() const { + return {}; +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/sources/geojson_source_impl.hpp b/src/mbgl/style/sources/geojson_source_impl.hpp index dece1269f8..a524bab9f2 100644 --- a/src/mbgl/style/sources/geojson_source_impl.hpp +++ b/src/mbgl/style/sources/geojson_source_impl.hpp @@ -2,7 +2,7 @@ #include <mbgl/style/source_impl.hpp> #include <mbgl/style/sources/geojson_source.hpp> -#include <mbgl/util/variant.hpp> +#include <mbgl/util/range.hpp> namespace mbgl { @@ -19,25 +19,17 @@ public: class GeoJSONSource::Impl : public Source::Impl { public: - Impl(std::string id, Source&, const GeoJSONOptions); + Impl(std::string id, GeoJSONOptions); + Impl(const GeoJSONSource::Impl&, const GeoJSON&); ~Impl() final; - void setURL(std::string); - optional<std::string> getURL() const; Range<uint8_t> getZoomRange() const; - - void setGeoJSON(const GeoJSON&); GeoJSONData* getData() const; - void loadDescription(FileSource&) final; - std::unique_ptr<RenderSource> createRenderSource() const final; + optional<std::string> getAttribution() const final; private: - void _setGeoJSON(const GeoJSON&); - GeoJSONOptions options; - optional<std::string> url; - std::unique_ptr<AsyncRequest> req; std::unique_ptr<GeoJSONData> data; }; diff --git a/src/mbgl/style/sources/image_source.cpp b/src/mbgl/style/sources/image_source.cpp new file mode 100644 index 0000000000..9b60ba1a48 --- /dev/null +++ b/src/mbgl/style/sources/image_source.cpp @@ -0,0 +1,84 @@ +#include <mbgl/style/sources/image_source.hpp> +#include <mbgl/style/sources/image_source_impl.hpp> +#include <mbgl/util/geo.hpp> +#include <mbgl/style/source_observer.hpp> +#include <mbgl/util/premultiply.hpp> +#include <mbgl/storage/file_source.hpp> + +namespace mbgl { +namespace style { + +ImageSource::ImageSource(std::string id, const std::array<LatLng, 4> coords_) + : Source(makeMutable<Impl>(std::move(id), coords_)) { +} + +ImageSource::~ImageSource() = default; + +const ImageSource::Impl& ImageSource::impl() const { + return static_cast<const Impl&>(*baseImpl); +} + +void ImageSource::setCoordinates(const std::array<LatLng, 4>& coords_) { + baseImpl = makeMutable<Impl>(impl(), coords_); + observer->onSourceChanged(*this); +} + +std::array<LatLng, 4> ImageSource::getCoordinates() const { + return impl().getCoordinates(); +} + +void ImageSource::setURL(const std::string& url_) { + url = std::move(url_); + // Signal that the source description needs a reload + if (loaded || req) { + loaded = false; + req.reset(); + observer->onSourceDescriptionChanged(*this); + } +} + +void ImageSource::setImage(PremultipliedImage&& image_) { + url = {}; + if (req) { + req.reset(); + } + loaded = true; + baseImpl = makeMutable<Impl>(impl(), std::move(image_)); + observer->onSourceChanged(*this); +} + +optional<std::string> ImageSource::getURL() const { + return url; +} + +void ImageSource::loadDescription(FileSource& fileSource) { + if (!url) { + loaded = true; + } + + if (req || loaded) { + return; + } + const Resource imageResource { Resource::Image, *url, {}, Resource::Necessity::Required }; + + req = fileSource.request(imageResource, [this](Response res) { + if (res.error) { + observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(res.error->message))); + } else if (res.notModified) { + return; + } else if (res.noContent) { + observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty image url"))); + } else { + try { + baseImpl = makeMutable<Impl>(impl(), decodeImage(*res.data)); + } catch (...) { + observer->onSourceError(*this, std::current_exception()); + } + loaded = true; + observer->onSourceLoaded(*this); + } + }); +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/sources/image_source_impl.cpp b/src/mbgl/style/sources/image_source_impl.cpp new file mode 100644 index 0000000000..c1f31dbdc6 --- /dev/null +++ b/src/mbgl/style/sources/image_source_impl.cpp @@ -0,0 +1,38 @@ +#include <mbgl/style/sources/image_source_impl.hpp> +#include <mbgl/util/geo.hpp> + +namespace mbgl { +namespace style { + +ImageSource::Impl::Impl(std::string id_, std::array<LatLng, 4> coords_) + : Source::Impl(SourceType::Image, std::move(id_)), + coords(std::move(coords_)) { +} + +ImageSource::Impl::Impl(const Impl& other, std::array<LatLng, 4> coords_) + : Source::Impl(other), + coords(std::move(coords_)), + image(other.image) { +} + +ImageSource::Impl::Impl(const Impl& rhs, PremultipliedImage&& image_) + : Source::Impl(rhs), + coords(rhs.coords), + image(std::make_shared<PremultipliedImage>(std::move(image_))) { +} +ImageSource::Impl::~Impl() = default; + +std::shared_ptr<PremultipliedImage> ImageSource::Impl::getImage() const { + return image; +} + +std::array<LatLng, 4> ImageSource::Impl::getCoordinates() const { + return coords; +} + +optional<std::string> ImageSource::Impl::getAttribution() const { + return {}; +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/sources/image_source_impl.hpp b/src/mbgl/style/sources/image_source_impl.hpp new file mode 100644 index 0000000000..1e1b005a32 --- /dev/null +++ b/src/mbgl/style/sources/image_source_impl.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include <mbgl/style/source_impl.hpp> +#include <mbgl/style/sources/image_source.hpp> +#include <mbgl/util/image.hpp> +#include <mbgl/util/geo.hpp> + +namespace mbgl { + +namespace style { + +class ImageSource::Impl : public Source::Impl { +public: + Impl(std::string id, std::array<LatLng, 4> coords); + Impl(const Impl& rhs, std::array<LatLng, 4> coords); + Impl(const Impl& rhs, PremultipliedImage&& image); + + ~Impl() final; + + std::shared_ptr<PremultipliedImage> getImage() const; + std::array<LatLng, 4> getCoordinates() const; + + optional<std::string> getAttribution() const final; +private: + std::array<LatLng, 4> coords; + std::shared_ptr<PremultipliedImage> image; +}; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/sources/raster_source.cpp b/src/mbgl/style/sources/raster_source.cpp index 94fdbcef12..0a0412a4ed 100644 --- a/src/mbgl/style/sources/raster_source.cpp +++ b/src/mbgl/style/sources/raster_source.cpp @@ -1,21 +1,81 @@ #include <mbgl/style/sources/raster_source.hpp> #include <mbgl/style/sources/raster_source_impl.hpp> +#include <mbgl/style/source_observer.hpp> +#include <mbgl/style/conversion/json.hpp> +#include <mbgl/style/conversion/tileset.hpp> +#include <mbgl/storage/file_source.hpp> +#include <mbgl/util/mapbox.hpp> namespace mbgl { namespace style { -RasterSource::RasterSource(std::string id, variant<std::string, Tileset> urlOrTileset, uint16_t tileSize) - : Source(SourceType::Raster, std::make_unique<RasterSource::Impl>(std::move(id), *this, std::move(urlOrTileset), tileSize)), - impl(static_cast<Impl*>(baseImpl.get())) { +RasterSource::RasterSource(std::string id, variant<std::string, Tileset> urlOrTileset_, uint16_t tileSize) + : Source(makeMutable<Impl>(std::move(id), tileSize)), + urlOrTileset(std::move(urlOrTileset_)) { +} + +RasterSource::~RasterSource() = default; + +const RasterSource::Impl& RasterSource::impl() const { + return static_cast<const Impl&>(*baseImpl); +} + +const variant<std::string, Tileset>& RasterSource::getURLOrTileset() const { + return urlOrTileset; } optional<std::string> RasterSource::getURL() const { - auto urlOrTileset = impl->getURLOrTileset(); - if (urlOrTileset.is<std::string>()) { - return urlOrTileset.get<std::string>(); - } else { + if (urlOrTileset.is<Tileset>()) { return {}; } + + return urlOrTileset.get<std::string>(); +} + +uint16_t RasterSource::getTileSize() const { + return impl().getTileSize(); +} + +void RasterSource::loadDescription(FileSource& fileSource) { + if (urlOrTileset.is<Tileset>()) { + baseImpl = makeMutable<Impl>(impl(), urlOrTileset.get<Tileset>()); + loaded = true; + return; + } + + if (req) { + return; + } + + const std::string& url = urlOrTileset.get<std::string>(); + req = fileSource.request(Resource::source(url), [this, url](Response res) { + if (res.error) { + observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(res.error->message))); + } else if (res.notModified) { + return; + } else if (res.noContent) { + observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty TileJSON"))); + } else { + conversion::Error error; + optional<Tileset> tileset = conversion::convertJSON<Tileset>(*res.data, error); + if (!tileset) { + observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(error.message))); + return; + } + + util::mapbox::canonicalizeTileset(*tileset, url, getType(), getTileSize()); + bool changed = impl().getTileset() != *tileset; + + baseImpl = makeMutable<Impl>(impl(), *tileset); + loaded = true; + + observer->onSourceLoaded(*this); + + if (changed) { + observer->onSourceChanged(*this); + } + } + }); } } // namespace style diff --git a/src/mbgl/style/sources/raster_source_impl.cpp b/src/mbgl/style/sources/raster_source_impl.cpp index b85d221f2e..50dae1f07e 100644 --- a/src/mbgl/style/sources/raster_source_impl.cpp +++ b/src/mbgl/style/sources/raster_source_impl.cpp @@ -1,17 +1,32 @@ #include <mbgl/style/sources/raster_source_impl.hpp> -#include <mbgl/renderer/sources/render_raster_source.hpp> namespace mbgl { namespace style { -RasterSource::Impl::Impl(std::string id_, Source& base_, - variant<std::string, Tileset> urlOrTileset_, - uint16_t tileSize_) - : TileSourceImpl(SourceType::Raster, std::move(id_), base_, std::move(urlOrTileset_), tileSize_) { +RasterSource::Impl::Impl(std::string id_, uint16_t tileSize_) + : Source::Impl(SourceType::Raster, std::move(id_)), + tileSize(tileSize_) { } -std::unique_ptr<RenderSource> RasterSource::Impl::createRenderSource() const { - return std::make_unique<RenderRasterSource>(*this); +RasterSource::Impl::Impl(const Impl& other, Tileset tileset_) + : Source::Impl(other), + tileSize(other.tileSize), + tileset(std::move(tileset_)) { +} + +uint16_t RasterSource::Impl::getTileSize() const { + return tileSize; +} + +optional<Tileset> RasterSource::Impl::getTileset() const { + return tileset; +} + +optional<std::string> RasterSource::Impl::getAttribution() const { + if (!tileset) { + return {}; + } + return tileset->attribution; } } // namespace style diff --git a/src/mbgl/style/sources/raster_source_impl.hpp b/src/mbgl/style/sources/raster_source_impl.hpp index 4bc76560f8..c41d5485b2 100644 --- a/src/mbgl/style/sources/raster_source_impl.hpp +++ b/src/mbgl/style/sources/raster_source_impl.hpp @@ -1,16 +1,24 @@ #pragma once #include <mbgl/style/sources/raster_source.hpp> -#include <mbgl/style/tile_source_impl.hpp> +#include <mbgl/style/source_impl.hpp> namespace mbgl { namespace style { -class RasterSource::Impl : public TileSourceImpl { +class RasterSource::Impl : public Source::Impl { public: - Impl(std::string id, Source&, variant<std::string, Tileset>, uint16_t tileSize); + Impl(std::string id, uint16_t tileSize); + Impl(const Impl&, Tileset); - std::unique_ptr<RenderSource> createRenderSource() const final; + optional<Tileset> getTileset() const; + uint16_t getTileSize() const; + + optional<std::string> getAttribution() const final; + +private: + uint16_t tileSize; + optional<Tileset> tileset; }; } // namespace style diff --git a/src/mbgl/style/sources/vector_source.cpp b/src/mbgl/style/sources/vector_source.cpp index 4bcd3b8985..ccdd453c75 100644 --- a/src/mbgl/style/sources/vector_source.cpp +++ b/src/mbgl/style/sources/vector_source.cpp @@ -1,21 +1,78 @@ #include <mbgl/style/sources/vector_source.hpp> #include <mbgl/style/sources/vector_source_impl.hpp> +#include <mbgl/style/source_observer.hpp> +#include <mbgl/style/conversion/json.hpp> +#include <mbgl/style/conversion/tileset.hpp> +#include <mbgl/storage/file_source.hpp> +#include <mbgl/util/mapbox.hpp> +#include <mbgl/util/constants.hpp> namespace mbgl { namespace style { -VectorSource::VectorSource(std::string id, variant<std::string, Tileset> urlOrTileset) - : Source(SourceType::Vector, std::make_unique<VectorSource::Impl>(std::move(id), *this, std::move(urlOrTileset))), - impl(static_cast<Impl*>(baseImpl.get())) { +VectorSource::VectorSource(std::string id, variant<std::string, Tileset> urlOrTileset_) + : Source(makeMutable<Impl>(std::move(id))), + urlOrTileset(std::move(urlOrTileset_)) { +} + +VectorSource::~VectorSource() = default; + +const VectorSource::Impl& VectorSource::impl() const { + return static_cast<const Impl&>(*baseImpl); +} + +const variant<std::string, Tileset>& VectorSource::getURLOrTileset() const { + return urlOrTileset; } optional<std::string> VectorSource::getURL() const { - auto urlOrTileset = impl->getURLOrTileset(); - if (urlOrTileset.is<std::string>()) { - return urlOrTileset.get<std::string>(); - } else { + if (urlOrTileset.is<Tileset>()) { return {}; } + + return urlOrTileset.get<std::string>(); +} + +void VectorSource::loadDescription(FileSource& fileSource) { + if (urlOrTileset.is<Tileset>()) { + baseImpl = makeMutable<Impl>(impl(), urlOrTileset.get<Tileset>()); + loaded = true; + return; + } + + if (req) { + return; + } + + const std::string& url = urlOrTileset.get<std::string>(); + req = fileSource.request(Resource::source(url), [this, url](Response res) { + if (res.error) { + observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(res.error->message))); + } else if (res.notModified) { + return; + } else if (res.noContent) { + observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty TileJSON"))); + } else { + conversion::Error error; + optional<Tileset> tileset = conversion::convertJSON<Tileset>(*res.data, error); + if (!tileset) { + observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(error.message))); + return; + } + + util::mapbox::canonicalizeTileset(*tileset, url, getType(), util::tileSize); + bool changed = impl().getTileset() != *tileset; + + baseImpl = makeMutable<Impl>(impl(), *tileset); + loaded = true; + + observer->onSourceLoaded(*this); + + if (changed) { + observer->onSourceChanged(*this); + } + } + }); } } // namespace style diff --git a/src/mbgl/style/sources/vector_source_impl.cpp b/src/mbgl/style/sources/vector_source_impl.cpp index 158abf8575..b06f0557bf 100644 --- a/src/mbgl/style/sources/vector_source_impl.cpp +++ b/src/mbgl/style/sources/vector_source_impl.cpp @@ -1,16 +1,26 @@ #include <mbgl/style/sources/vector_source_impl.hpp> -#include <mbgl/renderer/sources/render_vector_source.hpp> -#include <mbgl/util/constants.hpp> namespace mbgl { namespace style { -VectorSource::Impl::Impl(std::string id_, Source& base_, variant<std::string, Tileset> urlOrTileset_) - : TileSourceImpl(SourceType::Vector, std::move(id_), base_, std::move(urlOrTileset_), util::tileSize) { +VectorSource::Impl::Impl(std::string id_) + : Source::Impl(SourceType::Vector, std::move(id_)) { } -std::unique_ptr<RenderSource> VectorSource::Impl::createRenderSource() const { - return std::make_unique<RenderVectorSource>(*this); +VectorSource::Impl::Impl(const Impl& other, Tileset tileset_) + : Source::Impl(other), + tileset(std::move(tileset_)) { +} + +optional<Tileset> VectorSource::Impl::getTileset() const { + return tileset; +} + +optional<std::string> VectorSource::Impl::getAttribution() const { + if (!tileset) { + return {}; + } + return tileset->attribution; } } // namespace style diff --git a/src/mbgl/style/sources/vector_source_impl.hpp b/src/mbgl/style/sources/vector_source_impl.hpp index 844739948c..5e559b9266 100644 --- a/src/mbgl/style/sources/vector_source_impl.hpp +++ b/src/mbgl/style/sources/vector_source_impl.hpp @@ -1,16 +1,22 @@ #pragma once #include <mbgl/style/sources/vector_source.hpp> -#include <mbgl/style/tile_source_impl.hpp> +#include <mbgl/style/source_impl.hpp> namespace mbgl { namespace style { -class VectorSource::Impl : public TileSourceImpl { +class VectorSource::Impl : public Source::Impl { public: - Impl(std::string id, Source&, variant<std::string, Tileset>); + Impl(std::string id); + Impl(const Impl&, Tileset); - std::unique_ptr<RenderSource> createRenderSource() const final; + optional<Tileset> getTileset() const; + + optional<std::string> getAttribution() const final; + +private: + optional<Tileset> tileset; }; } // namespace style diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index f1ac22082b..bd8631fc52 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -1,813 +1,133 @@ #include <mbgl/style/style.hpp> -#include <mbgl/style/observer.hpp> -#include <mbgl/style/source_impl.hpp> -#include <mbgl/style/layers/symbol_layer.hpp> -#include <mbgl/style/layers/symbol_layer_impl.hpp> -#include <mbgl/style/layers/custom_layer.hpp> -#include <mbgl/style/layers/custom_layer_impl.hpp> -#include <mbgl/style/layers/background_layer.hpp> -#include <mbgl/style/layers/background_layer_impl.hpp> -#include <mbgl/style/layers/fill_layer.hpp> -#include <mbgl/style/layers/fill_extrusion_layer.hpp> -#include <mbgl/style/layers/line_layer.hpp> -#include <mbgl/style/layers/circle_layer.hpp> -#include <mbgl/style/layers/raster_layer.hpp> -#include <mbgl/style/layer_impl.hpp> -#include <mbgl/style/parser.hpp> -#include <mbgl/style/transition_options.hpp> -#include <mbgl/style/class_dictionary.hpp> -#include <mbgl/sprite/sprite_atlas.hpp> -#include <mbgl/text/glyph_atlas.hpp> -#include <mbgl/geometry/line_atlas.hpp> -#include <mbgl/renderer/update_parameters.hpp> -#include <mbgl/renderer/cascade_parameters.hpp> -#include <mbgl/renderer/property_evaluation_parameters.hpp> -#include <mbgl/renderer/tile_parameters.hpp> -#include <mbgl/renderer/render_source.hpp> -#include <mbgl/renderer/render_item.hpp> -#include <mbgl/renderer/render_tile.hpp> -#include <mbgl/renderer/render_background_layer.hpp> -#include <mbgl/renderer/render_circle_layer.hpp> -#include <mbgl/renderer/render_custom_layer.hpp> -#include <mbgl/renderer/render_fill_extrusion_layer.hpp> -#include <mbgl/renderer/render_fill_layer.hpp> -#include <mbgl/renderer/render_line_layer.hpp> -#include <mbgl/renderer/render_raster_layer.hpp> -#include <mbgl/renderer/render_symbol_layer.hpp> -#include <mbgl/tile/tile.hpp> -#include <mbgl/util/constants.hpp> -#include <mbgl/util/exception.hpp> -#include <mbgl/util/geometry.hpp> -#include <mbgl/util/string.hpp> -#include <mbgl/util/logging.hpp> -#include <mbgl/util/math.hpp> -#include <mbgl/util/std.hpp> -#include <mbgl/math/minmax.hpp> -#include <mbgl/map/query.hpp> - -#include <algorithm> +#include <mbgl/style/style_impl.hpp> +#include <mbgl/style/light.hpp> +#include <mbgl/style/image.hpp> +#include <mbgl/style/source.hpp> +#include <mbgl/style/layer.hpp> namespace mbgl { namespace style { -static Observer nullObserver; - -struct QueueSourceReloadVisitor { - UpdateBatch& updateBatch; - - // No need to reload sources for these types; their visibility can change but - // they don't participate in layout. - void operator()(CustomLayer&) {} - void operator()(RasterLayer&) {} - void operator()(BackgroundLayer&) {} - - template <class VectorLayer> - void operator()(VectorLayer& layer) { - updateBatch.sourceIDs.insert(layer.getSourceID()); - } -}; - -Style::Style(Scheduler& scheduler_, FileSource& fileSource_, float pixelRatio) - : scheduler(scheduler_), - fileSource(fileSource_), - glyphAtlas(std::make_unique<GlyphAtlas>(Size{ 2048, 2048 }, fileSource)), - spriteAtlas(std::make_unique<SpriteAtlas>(Size{ 1024, 1024 }, pixelRatio)), - lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })), - light(std::make_unique<Light>()), - renderLight(std::make_unique<RenderLight>(light->impl)), - observer(&nullObserver) { - glyphAtlas->setObserver(this); - spriteAtlas->setObserver(this); - light->impl->setObserver(this); +Style::Style(Scheduler& scheduler, FileSource& fileSource, float pixelRatio) + : impl(std::make_unique<Impl>(scheduler, fileSource, pixelRatio)) { } -Style::~Style() { - for (const auto& source : sources) { - source->baseImpl->setObserver(nullptr); - } - - for (const auto& layer : layers) { - if (CustomLayer* customLayer = layer->as<CustomLayer>()) { - customLayer->impl->deinitialize(); - } - } +Style::~Style() = default; - glyphAtlas->setObserver(nullptr); - spriteAtlas->setObserver(nullptr); - light->impl->setObserver(nullptr); +void Style::loadJSON(const std::string& json) { + impl->loadJSON(json); } -bool Style::addClass(const std::string& className) { - if (hasClass(className)) return false; - classes.push_back(className); - return true; +void Style::loadURL(const std::string& url) { + impl->loadURL(url); } -bool Style::hasClass(const std::string& className) const { - return std::find(classes.begin(), classes.end(), className) != classes.end(); +std::string Style::getJSON() const { + return impl->getJSON(); } -bool Style::removeClass(const std::string& className) { - const auto it = std::find(classes.begin(), classes.end(), className); - if (it != classes.end()) { - classes.erase(it); - return true; - } - return false; +std::string Style::getURL() const { + return impl->getURL(); } -void Style::setClasses(const std::vector<std::string>& classNames) { - classes = classNames; +std::string Style::getName() const { + return impl->getName(); } -std::vector<std::string> Style::getClasses() const { - return classes; -} - -void Style::setTransitionOptions(const TransitionOptions& options) { - transitionOptions = options; +CameraOptions Style::getDefaultCamera() const { + return impl->getDefaultCamera(); } TransitionOptions Style::getTransitionOptions() const { - return transitionOptions; -} - -void Style::setJSON(const std::string& json) { - sources.clear(); - renderSources.clear(); - layers.clear(); - renderLayers.clear(); - classes.clear(); - transitionOptions = {}; - updateBatch = {}; - - Parser parser; - auto error = parser.parse(json); - - if (error) { - std::string message = "Failed to parse style: " + util::toString(error); - Log::Error(Event::ParseStyle, message.c_str()); - observer->onStyleError(std::make_exception_ptr(util::StyleParseException(message))); - observer->onResourceError(error); - return; - } - - for (auto& source : parser.sources) { - addSource(std::move(source)); - } - - for (auto& layer : parser.layers) { - addLayer(std::move(layer)); - } - - name = parser.name; - defaultLatLng = parser.latLng; - defaultZoom = parser.zoom; - defaultBearing = parser.bearing; - defaultPitch = parser.pitch; - setLight(std::make_unique<Light>(parser.light)); - - glyphAtlas->setURL(parser.glyphURL); - spriteAtlas->load(parser.spriteURL, scheduler, fileSource); - - loaded = true; - - observer->onStyleLoaded(); -} - -void Style::addSource(std::unique_ptr<Source> source) { - // Guard against duplicate source ids - auto it = std::find_if(sources.begin(), sources.end(), [&](const auto& existing) { - return existing->getID() == source->getID(); - }); - - if (it != sources.end()) { - std::string msg = "Source " + source->getID() + " already exists"; - throw std::runtime_error(msg.c_str()); - } - - source->baseImpl->setObserver(this); - source->baseImpl->loadDescription(fileSource); - - std::unique_ptr<RenderSource> renderSource = source->baseImpl->createRenderSource(); - renderSource->setObserver(this); - renderSources.emplace_back(std::move(renderSource)); - - sources.emplace_back(std::move(source)); -} - -struct SourceIdUsageEvaluator { - const std::string& sourceId; - - bool operator()(BackgroundLayer&) { return false; } - bool operator()(CustomLayer&) { return false; } - - template <class LayerType> - bool operator()(LayerType& layer) { - return layer.getSourceID() == sourceId; - } -}; - -std::unique_ptr<Source> Style::removeSource(const std::string& id) { - // Check if source is in use - SourceIdUsageEvaluator sourceIdEvaluator {id}; - auto layerIt = std::find_if(layers.begin(), layers.end(), [&](const auto& layer) { - return layer->accept(sourceIdEvaluator); - }); - - if (layerIt != layers.end()) { - Log::Warning(Event::General, "Source '%s' is in use, cannot remove", id.c_str()); - return nullptr; - } - - auto it = std::find_if(sources.begin(), sources.end(), [&](const auto& source) { - return source->getID() == id; - }); - - if (it == sources.end()) { - return nullptr; - } - - util::erase_if(renderSources, [&](const auto& source) { - return source->baseImpl.id == id; - }); - - auto source = std::move(*it); - source->baseImpl->setObserver(nullptr); - sources.erase(it); - updateBatch.sourceIDs.erase(id); - - return source; -} - -std::vector<const Layer*> Style::getLayers() const { - std::vector<const Layer*> result; - result.reserve(layers.size()); - for (const auto& layer : layers) { - result.push_back(layer.get()); - } - return result; -} - -std::vector<Layer*> Style::getLayers() { - std::vector<Layer*> result; - result.reserve(layers.size()); - for (auto& layer : layers) { - result.push_back(layer.get()); - } - return result; -} - -std::vector<std::unique_ptr<Layer>>::const_iterator Style::findLayer(const std::string& id) const { - return std::find_if(layers.begin(), layers.end(), [&](const auto& layer) { - return layer->baseImpl->id == id; - }); -} - -Layer* Style::getLayer(const std::string& id) const { - auto it = findLayer(id); - return it != layers.end() ? it->get() : nullptr; -} - -Layer* Style::addLayer(std::unique_ptr<Layer> layer, optional<std::string> before) { - // TODO: verify source - - // Guard against duplicate layer ids - auto it = std::find_if(layers.begin(), layers.end(), [&](const auto& existing) { - return existing->getID() == layer->getID(); - }); - - if (it != layers.end()) { - throw std::runtime_error(std::string{"Layer "} + layer->getID() + " already exists"); - } - - if (CustomLayer* customLayer = layer->as<CustomLayer>()) { - customLayer->impl->initialize(); - } - - layer->baseImpl->setObserver(this); - layer->accept(QueueSourceReloadVisitor { updateBatch }); - - auto added = layers.emplace(before ? findLayer(*before) : layers.end(), std::move(layer))->get(); - renderLayers.emplace(before ? findRenderLayer(*before) : renderLayers.end(), added->baseImpl->createRenderLayer()); - return std::move(added); -} - -std::unique_ptr<Layer> Style::removeLayer(const std::string& id) { - auto it = std::find_if(layers.begin(), layers.end(), [&](const auto& layer) { - return layer->baseImpl->id == id; - }); - - if (it == layers.end()) - return nullptr; - - auto layer = std::move(*it); - - if (CustomLayer* customLayer = layer->as<CustomLayer>()) { - customLayer->impl->deinitialize(); - } - - layer->baseImpl->setObserver(nullptr); - layers.erase(it); - removeRenderLayer(id); - return layer; -} - -std::vector<const RenderLayer*> Style::getRenderLayers() const { - std::vector<const RenderLayer*> result; - result.reserve(renderLayers.size()); - for (const auto& layer : renderLayers) { - result.push_back(layer.get()); - } - return result; -} - -std::vector<RenderLayer*> Style::getRenderLayers() { - std::vector<RenderLayer*> result; - result.reserve(renderLayers.size()); - for (auto& layer : renderLayers) { - result.push_back(layer.get()); - } - return result; -} - -std::vector<std::unique_ptr<RenderLayer>>::const_iterator Style::findRenderLayer(const std::string& id) const { - return std::find_if(renderLayers.begin(), renderLayers.end(), [&](const auto& layer) { - return layer->baseImpl.id == id; - }); -} - -RenderLayer* Style::getRenderLayer(const std::string& id) const { - auto it = findRenderLayer(id); - return it != renderLayers.end() ? it->get() : nullptr; -} - -void Style::removeRenderLayer(const std::string& id) { - auto it = std::find_if(renderLayers.begin(), renderLayers.end(), [&](const auto& layer) { - return layer->baseImpl.id == id; - }); - - if (it != renderLayers.end()) { - renderLayers.erase(it); - } -} - -void Style::setLight(std::unique_ptr<Light> light_) { - light = std::move(light_); - light->impl->setObserver(this); - - // Copy renderlight to preserve the initialised - // transitioning light properties - renderLight = renderLight->copy(light->impl); - - onLightChanged(*light); -} - -Light* Style::getLight() const { - return light.get(); -} - -RenderLight* Style::getRenderLight() const { - return renderLight.get(); + return impl->getTransitionOptions(); } -std::string Style::getName() const { - return name; +void Style::setTransitionOptions(const TransitionOptions& options) { + impl->mutated = true; + impl->setTransitionOptions(options); } -LatLng Style::getDefaultLatLng() const { - return defaultLatLng; +void Style::setLight(std::unique_ptr<Light> light) { + impl->setLight(std::move(light)); } -double Style::getDefaultZoom() const { - return defaultZoom; +Light* Style::getLight() { + impl->mutated = true; + return impl->getLight(); } -double Style::getDefaultBearing() const { - return defaultBearing; +const Light* Style::getLight() const { + return impl->getLight(); } -double Style::getDefaultPitch() const { - return defaultPitch; +const Image* Style::getImage(const std::string& name) const { + return impl->getImage(name); } -void Style::update(const UpdateParameters& parameters) { - bool zoomChanged = zoomHistory.update(parameters.transformState.getZoom(), parameters.timePoint); - - std::vector<ClassID> classIDs; - for (const auto& className : classes) { - classIDs.push_back(ClassDictionary::Get().lookup(className)); - } - classIDs.push_back(ClassID::Default); - - const CascadeParameters cascadeParameters { - classIDs, - parameters.timePoint, - parameters.mode == MapMode::Continuous ? transitionOptions : TransitionOptions() - }; - - const PropertyEvaluationParameters evaluationParameters { - zoomHistory, - parameters.timePoint, - parameters.mode == MapMode::Continuous ? util::DEFAULT_FADE_DURATION : Duration::zero() - }; - - const TileParameters tileParameters(parameters.pixelRatio, - parameters.debugOptions, - parameters.transformState, - parameters.scheduler, - parameters.fileSource, - parameters.mode, - parameters.annotationManager, - *this); - - const bool cascade = parameters.updateFlags & Update::Classes; - const bool evaluate = cascade || zoomChanged || parameters.updateFlags & Update::RecalculateStyle; - - if (cascade) { - renderLight->transition(cascadeParameters); - } - - if (evaluate || renderLight->hasTransition()) { - renderLight->evaluate(evaluationParameters); - } - - for (const auto& renderSource : renderSources) { - renderSource->enabled = false; - } - - for (const auto& layer : renderLayers) { - if (cascade) { - layer->cascade(cascadeParameters); - } - - if (evaluate || layer->hasTransition()) { - layer->evaluate(evaluationParameters); - } - - if (layer->needsRendering(zoomHistory.lastZoom)) { - if (RenderSource* renderSource = getRenderSource(layer->baseImpl.source)) { - renderSource->enabled = true; - } - } - } - - for (const auto& renderSource : renderSources) { - bool updated = updateBatch.sourceIDs.count(renderSource->baseImpl.id); - if (renderSource->enabled) { - if (updated) { - renderSource->reloadTiles(); - } - renderSource->updateTiles(tileParameters); - } else if (updated) { - renderSource->invalidateTiles(); - } else { - renderSource->removeTiles(); - } - } - - updateBatch.sourceIDs.clear(); +void Style::addImage(std::unique_ptr<Image> image) { + impl->mutated = true; + impl->addImage(std::move(image)); } -std::vector<const Source*> Style::getSources() const { - std::vector<const Source*> result; - result.reserve(sources.size()); - for (const auto& source : sources) { - result.push_back(source.get()); - } - return result; +void Style::removeImage(const std::string& name) { + impl->mutated = true; + impl->removeImage(name); } std::vector<Source*> Style::getSources() { - std::vector<Source*> result; - result.reserve(sources.size()); - for (auto& source : sources) { - result.push_back(source.get()); - } - return result; + impl->mutated = true; + return impl->getSources(); } -Source* Style::getSource(const std::string& id) const { - const auto it = std::find_if(sources.begin(), sources.end(), [&](const auto& source) { - return source->getID() == id; - }); - - return it != sources.end() ? it->get() : nullptr; -} - -RenderSource* Style::getRenderSource(const std::string& id) const { - const auto it = std::find_if(renderSources.begin(), renderSources.end(), [&](const auto& source) { - return source->baseImpl.id == id; - }); - - return it != renderSources.end() ? it->get() : nullptr; -} - -bool Style::hasTransitions() const { - if (renderLight->hasTransition()) { - return true; - } - - for (const auto& layer : renderLayers) { - if (layer->hasTransition()) { - return true; - } - } - - return false; -} - -bool Style::isLoaded() const { - if (!loaded) { - return false; - } - - for (const auto& source: sources) { - if (!source->baseImpl->loaded) { - return false; - } - } - - for (const auto& renderSource: renderSources) { - if (!renderSource->isLoaded()) { - return false; - } - } - - if (!spriteAtlas->isLoaded()) { - return false; - } - - return true; -} - -RenderData Style::getRenderData(MapDebugOptions debugOptions, float angle) const { - RenderData result; - - for (const auto& renderSource: renderSources) { - if (renderSource->enabled) { - result.sources.insert(renderSource.get()); - } - } - - for (const auto& layer : renderLayers) { - if (!layer->needsRendering(zoomHistory.lastZoom)) { - continue; - } - - if (const RenderBackgroundLayer* background = layer->as<RenderBackgroundLayer>()) { - if (debugOptions & MapDebugOptions::Overdraw) { - // We want to skip glClear optimization in overdraw mode. - result.order.emplace_back(*layer); - continue; - } - const BackgroundPaintProperties::Evaluated& paint = background->evaluated; - if (layer.get() == renderLayers[0].get() && paint.get<BackgroundPattern>().from.empty()) { - // This is a solid background. We can use glClear(). - result.backgroundColor = paint.get<BackgroundColor>() * paint.get<BackgroundOpacity>(); - } else { - // This is a textured background, or not the bottommost layer. We need to render it with a quad. - result.order.emplace_back(*layer); - } - continue; - } - - if (layer->is<RenderCustomLayer>()) { - result.order.emplace_back(*layer); - continue; - } - - RenderSource* source = getRenderSource(layer->baseImpl.source); - if (!source) { - Log::Warning(Event::Render, "can't find source for layer '%s'", layer->baseImpl.id.c_str()); - continue; - } - - auto& renderTiles = source->getRenderTiles(); - const bool symbolLayer = layer->is<RenderSymbolLayer>(); - - // Sort symbol tiles in opposite y position, so tiles with overlapping - // symbols are drawn on top of each other, with lower symbols being - // drawn on top of higher symbols. - std::vector<std::reference_wrapper<RenderTile>> sortedTiles; - std::transform(renderTiles.begin(), renderTiles.end(), std::back_inserter(sortedTiles), - [](auto& pair) { return std::ref(pair.second); }); - if (symbolLayer) { - std::sort(sortedTiles.begin(), sortedTiles.end(), - [angle](const RenderTile& a, const RenderTile& b) { - Point<float> pa(a.id.canonical.x, a.id.canonical.y); - Point<float> pb(b.id.canonical.x, b.id.canonical.y); - - auto par = util::rotate(pa, angle); - auto pbr = util::rotate(pb, angle); - - return std::tie(par.y, par.x) < std::tie(pbr.y, pbr.x); - }); - } - - std::vector<std::reference_wrapper<RenderTile>> sortedTilesForInsertion; - for (auto tileIt = sortedTiles.begin(); tileIt != sortedTiles.end(); ++tileIt) { - auto& tile = tileIt->get(); - if (!tile.tile.isRenderable()) { - continue; - } - - // We're not clipping symbol layers, so when we have both parents and children of symbol - // layers, we drop all children in favor of their parent to avoid duplicate labels. - // See https://github.com/mapbox/mapbox-gl-native/issues/2482 - if (symbolLayer) { - bool skip = false; - // Look back through the buckets we decided to render to find out whether there is - // already a bucket from this layer that is a parent of this tile. Tiles are ordered - // by zoom level when we obtain them from getTiles(). - for (auto it = sortedTilesForInsertion.rbegin(); - it != sortedTilesForInsertion.rend(); ++it) { - if (tile.tile.id.isChildOf(it->get().tile.id)) { - skip = true; - break; - } - } - if (skip) { - continue; - } - } - - auto bucket = tile.tile.getBucket(*layer); - if (bucket) { - sortedTilesForInsertion.emplace_back(tile); - tile.used = true; - } - } - - result.order.emplace_back(*layer, std::move(sortedTilesForInsertion)); - } - - return result; -} - -std::vector<Feature> Style::queryRenderedFeatures(const ScreenLineString& geometry, - const TransformState& transformState, - const RenderedQueryOptions& options) const { - std::unordered_map<std::string, std::vector<Feature>> resultsByLayer; - - if (options.layerIDs) { - std::unordered_set<std::string> sourceIDs; - for (const auto& layerID : *options.layerIDs) { - if (Layer* layer = getLayer(layerID)) { - sourceIDs.emplace(layer->baseImpl->source); - } - } - for (const auto& sourceID : sourceIDs) { - if (RenderSource* renderSource = getRenderSource(sourceID)) { - auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, options); - std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin())); - } - } - } else { - for (const auto& renderSource : renderSources) { - auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, options); - std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin())); - } - } - - std::vector<Feature> result; - - if (resultsByLayer.empty()) { - return result; - } - - // Combine all results based on the style layer order. - for (const auto& layer : renderLayers) { - if (!layer->needsRendering(zoomHistory.lastZoom)) { - continue; - } - auto it = resultsByLayer.find(layer->baseImpl.id); - if (it != resultsByLayer.end()) { - std::move(it->second.begin(), it->second.end(), std::back_inserter(result)); - } - } - - return result; -} - -void Style::setSourceTileCacheSize(size_t size) { - for (const auto& renderSource : renderSources) { - renderSource->setCacheSize(size); - } -} - -void Style::onLowMemory() { - for (const auto& renderSource : renderSources) { - renderSource->onLowMemory(); - } -} - -void Style::setObserver(style::Observer* observer_) { - observer = observer_; -} - -void Style::onGlyphsLoaded(const FontStack& fontStack, const GlyphRange& glyphRange) { - observer->onGlyphsLoaded(fontStack, glyphRange); -} - -void Style::onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) { - lastError = error; - Log::Error(Event::Style, "Failed to load glyph range %d-%d for font stack %s: %s", - glyphRange.first, glyphRange.second, fontStackToString(fontStack).c_str(), util::toString(error).c_str()); - observer->onGlyphsError(fontStack, glyphRange, error); - observer->onResourceError(error); -} - -void Style::onSourceLoaded(Source& source) { - observer->onSourceLoaded(source); - observer->onUpdate(Update::Repaint); -} - -void Style::onSourceChanged(Source& source) { - observer->onSourceChanged(source); - observer->onUpdate(Update::Repaint); -} - -void Style::onSourceError(Source& source, std::exception_ptr error) { - lastError = error; - Log::Error(Event::Style, "Failed to load source %s: %s", - source.getID().c_str(), util::toString(error).c_str()); - observer->onSourceError(source, error); - observer->onResourceError(error); -} - -void Style::onSourceDescriptionChanged(Source& source) { - observer->onSourceDescriptionChanged(source); - if (!source.baseImpl->loaded) { - source.baseImpl->loadDescription(fileSource); - } -} - -void Style::onTileChanged(RenderSource&, const OverscaledTileID&) { - observer->onUpdate(Update::Repaint); +std::vector<const Source*> Style::getSources() const { + return const_cast<const Impl&>(*impl).getSources(); } -void Style::onTileError(RenderSource& source, const OverscaledTileID& tileID, std::exception_ptr error) { - lastError = error; - Log::Error(Event::Style, "Failed to load tile %s for source %s: %s", - util::toString(tileID).c_str(), source.baseImpl.id.c_str(), util::toString(error).c_str()); - observer->onResourceError(error); +Source* Style::getSource(const std::string& id) { + impl->mutated = true; + return impl->getSource(id); } -void Style::onSpriteLoaded() { - observer->onSpriteLoaded(); - observer->onUpdate(Update::Repaint); // For *-pattern properties. +const Source* Style::getSource(const std::string& id) const { + return impl->getSource(id); } -void Style::onSpriteError(std::exception_ptr error) { - lastError = error; - Log::Error(Event::Style, "Failed to load sprite: %s", util::toString(error).c_str()); - observer->onSpriteError(error); - observer->onResourceError(error); +void Style::addSource(std::unique_ptr<Source> source) { + impl->mutated = true; + impl->addSource(std::move(source)); } -void Style::onLayerFilterChanged(Layer& layer) { - layer.accept(QueueSourceReloadVisitor { updateBatch }); - observer->onUpdate(Update::Repaint); +std::unique_ptr<Source> Style::removeSource(const std::string& sourceID) { + impl->mutated = true; + return impl->removeSource(sourceID); } -void Style::onLayerVisibilityChanged(Layer& layer) { - layer.accept(QueueSourceReloadVisitor { updateBatch }); - observer->onUpdate(Update::RecalculateStyle); +std::vector<Layer*> Style::getLayers() { + impl->mutated = true; + return impl->getLayers(); } -void Style::onLayerPaintPropertyChanged(Layer&) { - observer->onUpdate(Update::RecalculateStyle | Update::Classes); +std::vector<const Layer*> Style::getLayers() const { + return const_cast<const Impl&>(*impl).getLayers(); } -void Style::onLayerDataDrivenPaintPropertyChanged(Layer& layer) { - layer.accept(QueueSourceReloadVisitor { updateBatch }); - observer->onUpdate(Update::RecalculateStyle | Update::Classes); +Layer* Style::getLayer(const std::string& layerID) { + impl->mutated = true; + return impl->getLayer(layerID); } -void Style::onLayerLayoutPropertyChanged(Layer& layer, const char * property) { - layer.accept(QueueSourceReloadVisitor { updateBatch }); - - // Recalculate the style for certain properties - observer->onUpdate((strcmp(property, "icon-size") == 0 || strcmp(property, "text-size") == 0) - ? Update::RecalculateStyle - : Update::Repaint); +const Layer* Style::getLayer(const std::string& layerID) const { + return impl->getLayer(layerID); } -void Style::onLightChanged(const Light&) { - observer->onUpdate(Update::Classes | Update::RecalculateStyle); +void Style::addLayer(std::unique_ptr<Layer> layer, const optional<std::string>& before) { + impl->mutated = true; + impl->addLayer(std::move(layer), before); } -void Style::dumpDebugLogs() const { - for (const auto& source : sources) { - source->baseImpl->dumpDebugLogs(); - } - - for (const auto& renderSource : renderSources) { - renderSource->dumpDebugLogs(); - } - - spriteAtlas->dumpDebugLogs(); +std::unique_ptr<Layer> Style::removeLayer(const std::string& id) { + impl->mutated = true; + return impl->removeLayer(id); } } // namespace style diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp deleted file mode 100644 index 7d235dc665..0000000000 --- a/src/mbgl/style/style.hpp +++ /dev/null @@ -1,192 +0,0 @@ -#pragma once - -#include <mbgl/style/transition_options.hpp> -#include <mbgl/style/observer.hpp> -#include <mbgl/style/source_observer.hpp> -#include <mbgl/renderer/render_source_observer.hpp> -#include <mbgl/style/layer_observer.hpp> -#include <mbgl/style/light_observer.hpp> -#include <mbgl/style/update_batch.hpp> -#include <mbgl/renderer/render_layer.hpp> -#include <mbgl/renderer/render_light.hpp> -#include <mbgl/text/glyph_atlas_observer.hpp> -#include <mbgl/sprite/sprite_atlas_observer.hpp> -#include <mbgl/map/mode.hpp> -#include <mbgl/map/zoom_history.hpp> - -#include <mbgl/util/noncopyable.hpp> -#include <mbgl/util/chrono.hpp> -#include <mbgl/util/optional.hpp> -#include <mbgl/util/feature.hpp> -#include <mbgl/util/geo.hpp> - -#include <cstdint> -#include <memory> -#include <string> -#include <vector> - -namespace mbgl { - -class FileSource; -class GlyphAtlas; -class SpriteAtlas; -class LineAtlas; -class RenderData; -class TransformState; -class RenderedQueryOptions; -class Scheduler; -class RenderLayer; -class RenderSource; -class UpdateParameters; - -namespace style { - -class Layer; -class QueryParameters; - -class Style : public GlyphAtlasObserver, - public SpriteAtlasObserver, - public SourceObserver, - public RenderSourceObserver, - public LayerObserver, - public LightObserver, - public util::noncopyable { -public: - Style(Scheduler&, FileSource&, float pixelRatio); - ~Style() override; - - void setJSON(const std::string&); - - void setObserver(Observer*); - - bool isLoaded() const; - - void update(const UpdateParameters&); - - bool hasTransitions() const; - - std::exception_ptr getLastError() const { - return lastError; - } - - std::vector<const Source*> getSources() const; - std::vector<Source*> getSources(); - Source* getSource(const std::string& id) const; - void addSource(std::unique_ptr<Source>); - std::unique_ptr<Source> removeSource(const std::string& sourceID); - - std::vector<const Layer*> getLayers() const; - std::vector<Layer*> getLayers(); - Layer* getLayer(const std::string& id) const; - Layer* addLayer(std::unique_ptr<Layer>, - optional<std::string> beforeLayerID = {}); - std::unique_ptr<Layer> removeLayer(const std::string& layerID); - - // Should be moved to Impl eventually - std::vector<const RenderLayer*> getRenderLayers() const; - std::vector<RenderLayer*> getRenderLayers(); - RenderLayer* getRenderLayer(const std::string& id) const; - - std::string getName() const; - LatLng getDefaultLatLng() const; - double getDefaultZoom() const; - double getDefaultBearing() const; - double getDefaultPitch() const; - - bool addClass(const std::string&); - bool removeClass(const std::string&); - void setClasses(const std::vector<std::string>&); - - TransitionOptions getTransitionOptions() const; - void setTransitionOptions(const TransitionOptions&); - - bool hasClass(const std::string&) const; - std::vector<std::string> getClasses() const; - - void setLight(std::unique_ptr<Light>); - Light* getLight() const; - RenderLight* getRenderLight() const; - - RenderData getRenderData(MapDebugOptions, float angle) const; - - std::vector<Feature> queryRenderedFeatures(const ScreenLineString& geometry, - const TransformState& transformState, - const RenderedQueryOptions& options) const; - - void setSourceTileCacheSize(size_t); - void onLowMemory(); - - void dumpDebugLogs() const; - - Scheduler& scheduler; - FileSource& fileSource; - std::unique_ptr<GlyphAtlas> glyphAtlas; - std::unique_ptr<SpriteAtlas> spriteAtlas; - std::unique_ptr<LineAtlas> lineAtlas; - - RenderSource* getRenderSource(const std::string& id) const; - -private: - std::vector<std::unique_ptr<Source>> sources; - std::vector<std::unique_ptr<RenderSource>> renderSources; - - std::vector<std::unique_ptr<Layer>> layers; - std::vector<std::unique_ptr<RenderLayer>> renderLayers; - std::vector<std::string> classes; - TransitionOptions transitionOptions; - - std::unique_ptr<Light> light; - std::unique_ptr<RenderLight> renderLight; - - // Defaults - std::string name; - LatLng defaultLatLng; - double defaultZoom = 0; - double defaultBearing = 0; - double defaultPitch = 0; - - std::vector<std::unique_ptr<Layer>>::const_iterator findLayer(const std::string& layerID) const; - std::vector<std::unique_ptr<RenderLayer>>::const_iterator findRenderLayer(const std::string&) const; - - // GlyphStoreObserver implementation. - void onGlyphsLoaded(const FontStack&, const GlyphRange&) override; - void onGlyphsError(const FontStack&, const GlyphRange&, std::exception_ptr) override; - - // SpriteStoreObserver implementation. - void onSpriteLoaded() override; - void onSpriteError(std::exception_ptr) override; - - // SourceObserver implementation. - void onSourceLoaded(Source&) override; - void onSourceChanged(Source&) override; - void onSourceError(Source&, std::exception_ptr) override; - void onSourceDescriptionChanged(Source&) override; - void onTileChanged(RenderSource&, const OverscaledTileID&) override; - void onTileError(RenderSource&, const OverscaledTileID&, std::exception_ptr) override; - - // LayerObserver implementation. - void onLayerFilterChanged(Layer&) override; - void onLayerVisibilityChanged(Layer&) override; - void onLayerPaintPropertyChanged(Layer&) override; - void onLayerDataDrivenPaintPropertyChanged(Layer&) override; - void onLayerLayoutPropertyChanged(Layer&, const char *) override; - - // LightObserver implementation. - void onLightChanged(const Light&) override; - - Observer nullObserver; - Observer* observer = &nullObserver; - - std::exception_ptr lastError; - - UpdateBatch updateBatch; - ZoomHistory zoomHistory; - - void removeRenderLayer(const std::string& layerID); - -public: - bool loaded = false; -}; - -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp new file mode 100644 index 0000000000..37907d3f60 --- /dev/null +++ b/src/mbgl/style/style_impl.cpp @@ -0,0 +1,364 @@ +#include <mbgl/style/style_impl.hpp> +#include <mbgl/style/observer.hpp> +#include <mbgl/style/source_impl.hpp> +#include <mbgl/style/layers/symbol_layer.hpp> +#include <mbgl/style/layers/custom_layer.hpp> +#include <mbgl/style/layers/background_layer.hpp> +#include <mbgl/style/layers/fill_layer.hpp> +#include <mbgl/style/layers/fill_extrusion_layer.hpp> +#include <mbgl/style/layers/line_layer.hpp> +#include <mbgl/style/layers/circle_layer.hpp> +#include <mbgl/style/layers/raster_layer.hpp> +#include <mbgl/style/layer_impl.hpp> +#include <mbgl/style/parser.hpp> +#include <mbgl/style/transition_options.hpp> +#include <mbgl/sprite/sprite_loader.hpp> +#include <mbgl/util/exception.hpp> +#include <mbgl/util/string.hpp> +#include <mbgl/util/logging.hpp> +#include <mbgl/storage/file_source.hpp> +#include <mbgl/storage/resource.hpp> +#include <mbgl/storage/response.hpp> + +namespace mbgl { +namespace style { + +static Observer nullObserver; + +Style::Impl::Impl(Scheduler& scheduler_, FileSource& fileSource_, float pixelRatio) + : scheduler(scheduler_), + fileSource(fileSource_), + spriteLoader(std::make_unique<SpriteLoader>(pixelRatio)), + light(std::make_unique<Light>()), + observer(&nullObserver) { + spriteLoader->setObserver(this); + light->setObserver(this); +} + +Style::Impl::~Impl() = default; + +void Style::Impl::loadJSON(const std::string& json_) { + lastError = nullptr; + observer->onStyleLoading(); + + url.clear(); + parse(json_); +} + +void Style::Impl::loadURL(const std::string& url_) { + lastError = nullptr; + observer->onStyleLoading(); + + loaded = false; + url = url_; + + styleRequest = fileSource.request(Resource::style(url), [this](Response res) { + // Once we get a fresh style, or the style is mutated, stop revalidating. + if (res.isFresh() || mutated) { + styleRequest.reset(); + } + + // Don't allow a loaded, mutated style to be overwritten with a new version. + if (mutated && loaded) { + return; + } + + if (res.error) { + const std::string message = "loading style failed: " + res.error->message; + Log::Error(Event::Setup, message.c_str()); + observer->onStyleError(std::make_exception_ptr(util::StyleLoadException(message))); + observer->onResourceError(std::make_exception_ptr(std::runtime_error(res.error->message))); + } else if (res.notModified || res.noContent) { + return; + } else { + parse(*res.data); + } + }); +} + +void Style::Impl::parse(const std::string& json_) { + Parser parser; + + if (auto error = parser.parse(json_)) { + std::string message = "Failed to parse style: " + util::toString(error); + Log::Error(Event::ParseStyle, message.c_str()); + observer->onStyleError(std::make_exception_ptr(util::StyleParseException(message))); + observer->onResourceError(error); + return; + } + + mutated = false; + loaded = false; + json = json_; + + sources.clear(); + layers.clear(); + images.clear(); + + transitionOptions = {}; + transitionOptions.duration = util::DEFAULT_TRANSITION_DURATION; + + for (auto& source : parser.sources) { + addSource(std::move(source)); + } + + for (auto& layer : parser.layers) { + addLayer(std::move(layer)); + } + + name = parser.name; + defaultCamera.center = parser.latLng; + defaultCamera.zoom = parser.zoom; + defaultCamera.angle = parser.bearing; + defaultCamera.pitch = parser.pitch; + + setLight(std::make_unique<Light>(parser.light)); + + spriteLoaded = false; + spriteLoader->load(parser.spriteURL, scheduler, fileSource); + glyphURL = parser.glyphURL; + + loaded = true; + observer->onStyleLoaded(); +} + +std::string Style::Impl::getJSON() const { + return json; +} + +std::string Style::Impl::getURL() const { + return url; +} + +void Style::Impl::setTransitionOptions(const TransitionOptions& options) { + transitionOptions = options; +} + +TransitionOptions Style::Impl::getTransitionOptions() const { + return transitionOptions; +} + +void Style::Impl::addSource(std::unique_ptr<Source> source) { + if (sources.get(source->getID())) { + std::string msg = "Source " + source->getID() + " already exists"; + throw std::runtime_error(msg.c_str()); + } + + source->setObserver(this); + source->loadDescription(fileSource); + + sources.add(std::move(source)); +} + +struct SourceIdUsageEvaluator { + const std::string& sourceId; + + bool operator()(BackgroundLayer&) { return false; } + bool operator()(CustomLayer&) { return false; } + + template <class LayerType> + bool operator()(LayerType& layer) { + return layer.getSourceID() == sourceId; + } +}; + +std::unique_ptr<Source> Style::Impl::removeSource(const std::string& id) { + // Check if source is in use + SourceIdUsageEvaluator sourceIdEvaluator {id}; + auto layerIt = std::find_if(layers.begin(), layers.end(), [&](const auto& layer) { + return layer->accept(sourceIdEvaluator); + }); + + if (layerIt != layers.end()) { + Log::Warning(Event::General, "Source '%s' is in use, cannot remove", id.c_str()); + return nullptr; + } + + std::unique_ptr<Source> source = sources.remove(id); + + if (source) { + source->setObserver(nullptr); + } + + return source; +} + +std::vector<Layer*> Style::Impl::getLayers() { + return layers.getWrappers(); +} + +std::vector<const Layer*> Style::Impl::getLayers() const { + auto wrappers = layers.getWrappers(); + return std::vector<const Layer*>(wrappers.begin(), wrappers.end()); +} + +Layer* Style::Impl::getLayer(const std::string& id) const { + return layers.get(id); +} + +Layer* Style::Impl::addLayer(std::unique_ptr<Layer> layer, optional<std::string> before) { + // TODO: verify source + + if (layers.get(layer->getID())) { + throw std::runtime_error(std::string{"Layer "} + layer->getID() + " already exists"); + } + + layer->setObserver(this); + observer->onUpdate(); + + return layers.add(std::move(layer), before); +} + +std::unique_ptr<Layer> Style::Impl::removeLayer(const std::string& id) { + std::unique_ptr<Layer> layer = layers.remove(id); + + if (layer) { + layer->setObserver(nullptr); + observer->onUpdate(); + } + + return layer; +} + +void Style::Impl::setLight(std::unique_ptr<Light> light_) { + light = std::move(light_); + light->setObserver(this); + onLightChanged(*light); +} + +Light* Style::Impl::getLight() const { + return light.get(); +} + +std::string Style::Impl::getName() const { + return name; +} + +CameraOptions Style::Impl::getDefaultCamera() const { + return defaultCamera; +} + +std::vector<Source*> Style::Impl::getSources() { + return sources.getWrappers(); +} + +std::vector<const Source*> Style::Impl::getSources() const { + auto wrappers = sources.getWrappers(); + return std::vector<const Source*>(wrappers.begin(), wrappers.end()); +} + +Source* Style::Impl::getSource(const std::string& id) const { + return sources.get(id); +} + +bool Style::Impl::isLoaded() const { + if (!loaded) { + return false; + } + + if (!spriteLoaded) { + return false; + } + + for (const auto& source: sources) { + if (!source->loaded) { + return false; + } + } + + return true; +} + +void Style::Impl::addImage(std::unique_ptr<style::Image> image) { + images.remove(image->getID()); // We permit using addImage to update. + images.add(std::move(image)); +} + +void Style::Impl::removeImage(const std::string& id) { + images.remove(id); +} + +const style::Image* Style::Impl::getImage(const std::string& id) const { + return images.get(id); +} + +void Style::Impl::setObserver(style::Observer* observer_) { + observer = observer_; +} + +void Style::Impl::onSourceLoaded(Source& source) { + sources.update(source); + observer->onSourceLoaded(source); + observer->onUpdate(); +} + +void Style::Impl::onSourceChanged(Source& source) { + sources.update(source); + observer->onSourceChanged(source); + observer->onUpdate(); +} + +void Style::Impl::onSourceError(Source& source, std::exception_ptr error) { + lastError = error; + Log::Error(Event::Style, "Failed to load source %s: %s", + source.getID().c_str(), util::toString(error).c_str()); + observer->onSourceError(source, error); + observer->onResourceError(error); +} + +void Style::Impl::onSourceDescriptionChanged(Source& source) { + sources.update(source); + observer->onSourceDescriptionChanged(source); + if (!source.loaded) { + source.loadDescription(fileSource); + } +} + +void Style::Impl::onSpriteLoaded(std::vector<std::unique_ptr<Image>>&& images_) { + for (auto& image : images_) { + addImage(std::move(image)); + } + spriteLoaded = true; + observer->onUpdate(); // For *-pattern properties. +} + +void Style::Impl::onSpriteError(std::exception_ptr error) { + lastError = error; + Log::Error(Event::Style, "Failed to load sprite: %s", util::toString(error).c_str()); + observer->onResourceError(error); +} + +void Style::Impl::onLayerChanged(Layer& layer) { + layers.update(layer); + observer->onUpdate(); +} + +void Style::Impl::onLightChanged(const Light&) { + observer->onUpdate(); +} + +void Style::Impl::dumpDebugLogs() const { + Log::Info(Event::General, "styleURL: %s", url.c_str()); + for (const auto& source : sources) { + source->dumpDebugLogs(); + } +} + +const std::string& Style::Impl::getGlyphURL() const { + return glyphURL; +} + +Immutable<std::vector<Immutable<Image::Impl>>> Style::Impl::getImageImpls() const { + return images.getImpls(); +} + +Immutable<std::vector<Immutable<Source::Impl>>> Style::Impl::getSourceImpls() const { + return sources.getImpls(); +} + +Immutable<std::vector<Immutable<Layer::Impl>>> Style::Impl::getLayerImpls() const { + return layers.getImpls(); +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/style_impl.hpp b/src/mbgl/style/style_impl.hpp new file mode 100644 index 0000000000..3dc222bfad --- /dev/null +++ b/src/mbgl/style/style_impl.hpp @@ -0,0 +1,144 @@ +#pragma once + +#include <mbgl/style/style.hpp> +#include <mbgl/style/transition_options.hpp> +#include <mbgl/style/observer.hpp> +#include <mbgl/style/source_observer.hpp> +#include <mbgl/style/layer_observer.hpp> +#include <mbgl/style/light_observer.hpp> +#include <mbgl/sprite/sprite_loader_observer.hpp> +#include <mbgl/style/image.hpp> +#include <mbgl/style/source.hpp> +#include <mbgl/style/layer.hpp> +#include <mbgl/style/collection.hpp> + +#include <mbgl/map/camera.hpp> + +#include <mbgl/util/noncopyable.hpp> +#include <mbgl/util/optional.hpp> +#include <mbgl/util/geo.hpp> + +#include <memory> +#include <string> +#include <vector> +#include <unordered_map> + +namespace mbgl { + +class Scheduler; +class FileSource; +class AsyncRequest; +class SpriteLoader; + +namespace style { + +class Style::Impl : public SpriteLoaderObserver, + public SourceObserver, + public LayerObserver, + public LightObserver, + public util::noncopyable { +public: + Impl(Scheduler&, FileSource&, float pixelRatio); + ~Impl() override; + + void loadJSON(const std::string&); + void loadURL(const std::string&); + + std::string getJSON() const; + std::string getURL() const; + + void setObserver(Observer*); + + bool isLoaded() const; + + std::exception_ptr getLastError() const { + return lastError; + } + + std::vector< Source*> getSources(); + std::vector<const Source*> getSources() const; + Source* getSource(const std::string& id) const; + + void addSource(std::unique_ptr<Source>); + std::unique_ptr<Source> removeSource(const std::string& sourceID); + + std::vector< Layer*> getLayers(); + std::vector<const Layer*> getLayers() const; + Layer* getLayer(const std::string& id) const; + + Layer* addLayer(std::unique_ptr<Layer>, + optional<std::string> beforeLayerID = {}); + std::unique_ptr<Layer> removeLayer(const std::string& layerID); + + std::string getName() const; + CameraOptions getDefaultCamera() const; + + TransitionOptions getTransitionOptions() const; + void setTransitionOptions(const TransitionOptions&); + + void setLight(std::unique_ptr<Light>); + Light* getLight() const; + + const style::Image* getImage(const std::string&) const; + void addImage(std::unique_ptr<style::Image>); + void removeImage(const std::string&); + + const std::string& getGlyphURL() const; + + Immutable<std::vector<Immutable<Image::Impl>>> getImageImpls() const; + Immutable<std::vector<Immutable<Source::Impl>>> getSourceImpls() const; + Immutable<std::vector<Immutable<Layer::Impl>>> getLayerImpls() const; + + void dumpDebugLogs() const; + + bool mutated = false; + bool loaded = false; + bool spriteLoaded = false; + +private: + void parse(const std::string&); + + Scheduler& scheduler; + FileSource& fileSource; + + std::string url; + std::string json; + + std::unique_ptr<AsyncRequest> styleRequest; + std::unique_ptr<SpriteLoader> spriteLoader; + + std::string glyphURL; + Collection<style::Image> images; + Collection<Source> sources; + Collection<Layer> layers; + TransitionOptions transitionOptions; + std::unique_ptr<Light> light; + + // Defaults + std::string name; + CameraOptions defaultCamera; + + // SpriteLoaderObserver implementation. + void onSpriteLoaded(std::vector<std::unique_ptr<Image>>&&) override; + void onSpriteError(std::exception_ptr) override; + + // SourceObserver implementation. + void onSourceLoaded(Source&) override; + void onSourceChanged(Source&) override; + void onSourceError(Source&, std::exception_ptr) override; + void onSourceDescriptionChanged(Source&) override; + + // LayerObserver implementation. + void onLayerChanged(Layer&) override; + + // LightObserver implementation. + void onLightChanged(const Light&) override; + + Observer nullObserver; + Observer* observer = &nullObserver; + + std::exception_ptr lastError; +}; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/tile_source_impl.cpp b/src/mbgl/style/tile_source_impl.cpp deleted file mode 100644 index d2ce3def9f..0000000000 --- a/src/mbgl/style/tile_source_impl.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include <mbgl/style/tile_source_impl.hpp> -#include <mbgl/style/source_observer.hpp> -#include <mbgl/style/conversion/json.hpp> -#include <mbgl/style/conversion/tileset.hpp> -#include <mbgl/util/mapbox.hpp> -#include <mbgl/storage/file_source.hpp> - -namespace mbgl { -namespace style { - -TileSourceImpl::TileSourceImpl(SourceType type_, std::string id_, Source& base_, - variant<std::string, Tileset> urlOrTileset_, - uint16_t tileSize_) - : Impl(type_, std::move(id_), base_), - urlOrTileset(std::move(urlOrTileset_)), - tileSize(tileSize_) { -} - -TileSourceImpl::~TileSourceImpl() = default; - -void TileSourceImpl::loadDescription(FileSource& fileSource) { - if (urlOrTileset.is<Tileset>()) { - tileset = urlOrTileset.get<Tileset>(); - loaded = true; - return; - } - - if (req) { - return; - } - - const std::string& url = urlOrTileset.get<std::string>(); - req = fileSource.request(Resource::source(url), [this, url](Response res) { - if (res.error) { - observer->onSourceError(base, std::make_exception_ptr(std::runtime_error(res.error->message))); - } else if (res.notModified) { - return; - } else if (res.noContent) { - observer->onSourceError(base, std::make_exception_ptr(std::runtime_error("unexpectedly empty TileJSON"))); - } else { - conversion::Error error; - optional<Tileset> newTileset = conversion::convertJSON<Tileset>(*res.data, error); - if (!newTileset) { - observer->onSourceError(base, std::make_exception_ptr(std::runtime_error(error.message))); - return; - } - - util::mapbox::canonicalizeTileset(*newTileset, url, type, tileSize); - bool attributionChanged = tileset.attribution != (*newTileset).attribution; - - tileset = *newTileset; - loaded = true; - - observer->onSourceLoaded(base); - if (attributionChanged) { - observer->onSourceChanged(base); - } - } - }); -} - -optional<Tileset> TileSourceImpl::getTileset() const { - if (loaded) { - return tileset; - } - return {}; -} - -optional<std::string> TileSourceImpl::getAttribution() const { - if (loaded && !tileset.attribution.empty()) { - return tileset.attribution; - } else { - return {}; - } -} - -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/tile_source_impl.hpp b/src/mbgl/style/tile_source_impl.hpp deleted file mode 100644 index 0e5a53add7..0000000000 --- a/src/mbgl/style/tile_source_impl.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include <mbgl/style/source_impl.hpp> -#include <mbgl/util/tileset.hpp> -#include <mbgl/util/variant.hpp> -#include <mbgl/util/optional.hpp> - -namespace mbgl { - -class AsyncRequest; - -namespace style { - -/* - Shared implementation for VectorSource and RasterSource. Should eventually - be refactored to use composition rather than inheritance. -*/ -class TileSourceImpl : public Source::Impl { -public: - TileSourceImpl(SourceType, std::string id, Source&, - variant<std::string, Tileset> urlOrTileset, - uint16_t tileSize); - ~TileSourceImpl() override; - - void loadDescription(FileSource&) final; - - uint16_t getTileSize() const { - return tileSize; - } - - const variant<std::string, Tileset>& getURLOrTileset() const { - return urlOrTileset; - } - - optional<std::string> getAttribution() const override; - optional<Tileset> getTileset() const; - -protected: - const variant<std::string, Tileset> urlOrTileset; - const uint16_t tileSize; - - Tileset tileset; - std::unique_ptr<AsyncRequest> req; -}; - -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/types.cpp b/src/mbgl/style/types.cpp index b37e73ffb1..0a1781e01b 100644 --- a/src/mbgl/style/types.cpp +++ b/src/mbgl/style/types.cpp @@ -11,6 +11,7 @@ MBGL_DEFINE_ENUM(SourceType, { { SourceType::GeoJSON, "geojson" }, { SourceType::Video, "video" }, { SourceType::Annotations, "annotations" }, + { SourceType::Image, "image" }, }); MBGL_DEFINE_ENUM(VisibilityType, { @@ -52,16 +53,16 @@ MBGL_DEFINE_ENUM(SymbolPlacementType, { { SymbolPlacementType::Line, "line" }, }); -MBGL_DEFINE_ENUM(TextAnchorType, { - { TextAnchorType::Center, "center" }, - { TextAnchorType::Left, "left" }, - { TextAnchorType::Right, "right" }, - { TextAnchorType::Top, "top" }, - { TextAnchorType::Bottom, "bottom" }, - { TextAnchorType::TopLeft, "top-left" }, - { TextAnchorType::TopRight, "top-right" }, - { TextAnchorType::BottomLeft, "bottom-left" }, - { TextAnchorType::BottomRight, "bottom-right" } +MBGL_DEFINE_ENUM(SymbolAnchorType, { + { SymbolAnchorType::Center, "center" }, + { SymbolAnchorType::Left, "left" }, + { SymbolAnchorType::Right, "right" }, + { SymbolAnchorType::Top, "top" }, + { SymbolAnchorType::Bottom, "bottom" }, + { SymbolAnchorType::TopLeft, "top-left" }, + { SymbolAnchorType::TopRight, "top-right" }, + { SymbolAnchorType::BottomLeft, "bottom-left" }, + { SymbolAnchorType::BottomRight, "bottom-right" } }); MBGL_DEFINE_ENUM(TextJustifyType, { diff --git a/src/mbgl/style/update_batch.hpp b/src/mbgl/style/update_batch.hpp deleted file mode 100644 index 562df52afa..0000000000 --- a/src/mbgl/style/update_batch.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include <unordered_set> -#include <string> - -namespace mbgl { -namespace style { - -class UpdateBatch { -public: - std::unordered_set<std::string> sourceIDs; -}; - -} // namespace style -} // namespace mbgl |