diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2016-10-28 16:39:50 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2017-02-02 09:44:42 -0800 |
commit | 141e995806576364d185626176c1b993fc519291 (patch) | |
tree | ecdc41fc7699f2a1a9e9456157348451ebe99597 /src/mbgl/style | |
parent | 6a6bddb4537004cc1bfc506e76772de74d33f3f7 (diff) | |
download | qtlocation-mapboxgl-141e995806576364d185626176c1b993fc519291.tar.gz |
[core] Add support for data-driven styling
Diffstat (limited to 'src/mbgl/style')
49 files changed, 957 insertions, 387 deletions
diff --git a/src/mbgl/style/bucket_parameters.cpp b/src/mbgl/style/bucket_parameters.cpp index e641120c5e..2b02ac4a4a 100644 --- a/src/mbgl/style/bucket_parameters.cpp +++ b/src/mbgl/style/bucket_parameters.cpp @@ -1,21 +1,7 @@ #include <mbgl/style/bucket_parameters.hpp> -#include <mbgl/style/filter_evaluator.hpp> -#include <mbgl/tile/geometry_tile_data.hpp> namespace mbgl { namespace style { -void BucketParameters::eachFilteredFeature(const Filter& filter, - const GeometryTileLayer& layer, - std::function<void (const GeometryTileFeature&, std::size_t index, const std::string& layerName)> function) { - auto name = layer.getName(); - for (std::size_t i = 0; !cancelled() && i < layer.featureCount(); i++) { - auto feature = layer.getFeature(i); - if (!filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); })) - continue; - function(*feature, i, name); - } -} - } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/bucket_parameters.hpp b/src/mbgl/style/bucket_parameters.hpp index d5e05c5dd2..d0edbcac30 100644 --- a/src/mbgl/style/bucket_parameters.hpp +++ b/src/mbgl/style/bucket_parameters.hpp @@ -2,33 +2,14 @@ #include <mbgl/map/mode.hpp> #include <mbgl/tile/tile_id.hpp> -#include <mbgl/style/filter.hpp> - -#include <atomic> -#include <functional> namespace mbgl { - -class GeometryTileLayer; -class GeometryTileFeature; -class FeatureIndex; - namespace style { class BucketParameters { public: - const OverscaledTileID& tileID; - const std::atomic<bool>& obsolete; - FeatureIndex& featureIndex; + const OverscaledTileID tileID; const MapMode mode; - - bool cancelled() const { - return obsolete; - } - - void eachFilteredFeature(const Filter&, - const GeometryTileLayer&, - std::function<void (const GeometryTileFeature&, std::size_t index, const std::string& layerName)>); }; } // namespace style diff --git a/src/mbgl/style/conversion/stringify.hpp b/src/mbgl/style/conversion/stringify.hpp index d06b2f2814..71755bd9d6 100644 --- a/src/mbgl/style/conversion/stringify.hpp +++ b/src/mbgl/style/conversion/stringify.hpp @@ -214,20 +214,131 @@ void stringify(Writer& writer, const Undefined&) { writer.Null(); } -template <class Writer, class T> -void stringify(Writer& writer, const Function<T>& f) { - writer.StartObject(); - writer.Key("base"); - writer.Double(f.getBase()); - writer.Key("stops"); - writer.StartArray(); - for (const auto& stop : f.getStops()) { +template <class Writer> +void stringify(Writer& writer, const CategoricalValue& v) { + CategoricalValue::visit(v, [&] (const auto& v_) { stringify(writer, v_); }); +} + +template <class Writer> +class StringifyStops { +public: + Writer& writer; + + template <class T> + void operator()(const ExponentialStops<T>& f) { + writer.Key("type"); + writer.String("exponential"); + writer.Key("base"); + writer.Double(f.base); + writer.Key("stops"); + stringifyStops(f.stops); + } + + template <class T> + void operator()(const IntervalStops<T>& f) { + writer.Key("type"); + writer.String("interval"); + writer.Key("stops"); + stringifyStops(f.stops); + } + + template <class T> + void operator()(const CategoricalStops<T>& f) { + writer.Key("type"); + writer.String("categorical"); + writer.Key("stops"); + stringifyStops(f.stops); + } + + template <class T> + void operator()(const IdentityStops<T>&) { + writer.Key("type"); + writer.String("identity"); + } + + template <class T> + void operator()(const std::map<float, ExponentialStops<T>>& f) { + writer.Key("type"); + writer.String("exponential"); + if (!f.empty()) { + writer.Key("base"); + writer.Double(f.begin()->second.base); + } + writer.Key("stops"); + stringifyCompositeStops(f); + } + + template <class T> + void operator()(const std::map<float, IntervalStops<T>>& f) { + writer.Key("type"); + writer.String("interval"); + writer.Key("stops"); + stringifyCompositeStops(f); + } + + template <class T> + void operator()(const std::map<float, CategoricalStops<T>>& f) { + writer.Key("type"); + writer.String("categorical"); + writer.Key("stops"); + stringifyCompositeStops(f); + } + +private: + template <class K, class V> + void stringifyStops(const std::map<K, V>& stops) { writer.StartArray(); - writer.Double(stop.first); - stringify(writer, stop.second); + for (const auto& stop : stops) { + writer.StartArray(); + stringify(writer, stop.first); + stringify(writer, stop.second); + writer.EndArray(); + } writer.EndArray(); } - writer.EndArray(); + + template <class InnerStops> + void stringifyCompositeStops(const std::map<float, InnerStops>& stops) { + writer.StartArray(); + for (const auto& outer : stops) { + for (const auto& inner : outer.second.stops) { + writer.StartArray(); + writer.StartObject(); + writer.Key("zoom"); + writer.Double(outer.first); + writer.Key("value"); + stringify(writer, inner.first); + writer.EndObject(); + stringify(writer, inner.second); + writer.EndArray(); + } + } + writer.EndArray(); + } +}; + +template <class Writer, class T> +void stringify(Writer& writer, const CameraFunction<T>& f) { + writer.StartObject(); + CameraFunction<T>::Stops::visit(f.stops, StringifyStops<Writer> { writer }); + writer.EndObject(); +} + +template <class Writer, class T> +void stringify(Writer& writer, const SourceFunction<T>& f) { + writer.StartObject(); + writer.Key("property"); + writer.String(f.property); + SourceFunction<T>::Stops::visit(f.stops, StringifyStops<Writer> { writer }); + writer.EndObject(); +} + +template <class Writer, class T> +void stringify(Writer& writer, const CompositeFunction<T>& f) { + writer.StartObject(); + writer.Key("property"); + writer.String(f.property); + CompositeFunction<T>::Stops::visit(f.stops, StringifyStops<Writer> { writer }); writer.EndObject(); } @@ -238,7 +349,20 @@ void stringify(Writer& writer, const PropertyValue<T>& v) { template <class Property, class Writer, class T> void stringify(Writer& writer, const PropertyValue<T>& value) { - if (value) { + if (!value.isUndefined()) { + writer.Key(Property::key); + stringify(writer, value); + } +} + +template <class Writer, class T> +void stringify(Writer& writer, const DataDrivenPropertyValue<T>& v) { + v.evaluate([&] (const auto& v_) { stringify(writer, v_); }); +} + +template <class Property, class Writer, class T> +void stringify(Writer& writer, const DataDrivenPropertyValue<T>& value) { + if (!value.isUndefined()) { writer.Key(Property::key); stringify(writer, value); } diff --git a/src/mbgl/style/cross_faded_property_evaluator.cpp b/src/mbgl/style/cross_faded_property_evaluator.cpp index 4de939576e..796ca00bbf 100644 --- a/src/mbgl/style/cross_faded_property_evaluator.cpp +++ b/src/mbgl/style/cross_faded_property_evaluator.cpp @@ -17,21 +17,10 @@ Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const T& constant) const { } template <typename T> -T getBiggestStopLessThan(const Function<T>& function, float z) { - const auto& stops = function.getStops(); - for (uint32_t i = 0; i < stops.size(); i++) { - if (stops[i].first > z) { - return stops[i == 0 ? i : i - 1].second; - } - } - return stops.at(stops.size() - 1).second; -} - -template <typename T> -Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const Function<T>& function) const { - return calculate(getBiggestStopLessThan(function, parameters.z - 1.0f), - getBiggestStopLessThan(function, parameters.z), - getBiggestStopLessThan(function, parameters.z + 1.0f)); +Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const CameraFunction<T>& function) const { + return calculate(function.evaluate(parameters.z - 1.0f), + function.evaluate(parameters.z), + function.evaluate(parameters.z + 1.0f)); } template <typename T> diff --git a/src/mbgl/style/cross_faded_property_evaluator.hpp b/src/mbgl/style/cross_faded_property_evaluator.hpp index 70c8c0c978..c5642f5cfb 100644 --- a/src/mbgl/style/cross_faded_property_evaluator.hpp +++ b/src/mbgl/style/cross_faded_property_evaluator.hpp @@ -28,7 +28,7 @@ public: Faded<T> operator()(const Undefined&) const; Faded<T> operator()(const T& constant) const; - Faded<T> operator()(const Function<T>&) const; + Faded<T> operator()(const CameraFunction<T>&) const; private: Faded<T> calculate(const T& min, const T& mid, const T& max) const; diff --git a/src/mbgl/style/data_driven_property_evaluator.hpp b/src/mbgl/style/data_driven_property_evaluator.hpp new file mode 100644 index 0000000000..7a0ff9a094 --- /dev/null +++ b/src/mbgl/style/data_driven_property_evaluator.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include <mbgl/style/property_value.hpp> +#include <mbgl/style/property_evaluation_parameters.hpp> +#include <mbgl/style/possibly_evaluated_property_value.hpp> + +namespace mbgl { +namespace style { + +template <typename T> +class DataDrivenPropertyEvaluator { +public: + using ResultType = PossiblyEvaluatedPropertyValue<T>; + + DataDrivenPropertyEvaluator(const PropertyEvaluationParameters& parameters_, T defaultValue_) + : parameters(parameters_), + defaultValue(std::move(defaultValue_)) {} + + ResultType operator()(const Undefined&) const { + return ResultType(defaultValue); + } + + ResultType operator()(const T& constant) const { + return ResultType(constant); + } + + ResultType operator()(const CameraFunction<T>& function) const { + return ResultType(function.evaluate(parameters.z)); + } + + template <class Function> + ResultType operator()(const Function& function) const { + return ResultType(function); + } + +private: + const PropertyEvaluationParameters& parameters; + T defaultValue; +}; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/function.cpp b/src/mbgl/style/function.cpp deleted file mode 100644 index 02750c7d2e..0000000000 --- a/src/mbgl/style/function.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include <mbgl/style/function.hpp> -#include <mbgl/style/types.hpp> -#include <mbgl/util/color.hpp> -#include <mbgl/util/interpolate.hpp> - -#include <cmath> - -namespace mbgl { -namespace style { - -template <typename T> -T Function<T>::evaluate(float z) const { - bool smaller = false; - float smaller_z = 0.0f; - T smaller_val = T(); - bool larger = false; - float larger_z = 0.0f; - T larger_val = T(); - - for (uint32_t i = 0; i < stops.size(); i++) { - float stop_z = stops[i].first; - T stop_val = stops[i].second; - if (stop_z <= z && (!smaller || smaller_z < stop_z)) { - smaller = true; - smaller_z = stop_z; - smaller_val = stop_val; - } - if (stop_z >= z && (!larger || larger_z > stop_z)) { - larger = true; - larger_z = stop_z; - larger_val = stop_val; - } - } - - if (smaller && larger) { - if (larger_z == smaller_z || larger_val == smaller_val) { - return smaller_val; - } - const float zoomDiff = larger_z - smaller_z; - const float zoomProgress = z - smaller_z; - if (base == 1.0f) { - const float t = zoomProgress / zoomDiff; - return util::interpolate(smaller_val, larger_val, t); - } else { - const float t = (std::pow(base, zoomProgress) - 1) / (std::pow(base, zoomDiff) - 1); - return util::interpolate(smaller_val, larger_val, t); - } - } else if (larger) { - return larger_val; - } else if (smaller) { - return smaller_val; - } else { - // No stop defined. - assert(false); - return T(); - } -} - -template class Function<bool>; -template class Function<float>; -template class Function<Color>; -template class Function<std::vector<float>>; -template class Function<std::vector<std::string>>; -template class Function<std::array<float, 2>>; -template class Function<std::array<float, 4>>; - -template class Function<std::string>; -template class Function<TranslateAnchorType>; -template class Function<RotateAnchorType>; -template class Function<CirclePitchScaleType>; -template class Function<LineCapType>; -template class Function<LineJoinType>; -template class Function<SymbolPlacementType>; -template class Function<TextAnchorType>; -template class Function<TextJustifyType>; -template class Function<TextTransformType>; -template class Function<AlignmentType>; -template class Function<IconTextFitType>; - -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/function/categorical_stops.cpp b/src/mbgl/style/function/categorical_stops.cpp new file mode 100644 index 0000000000..bcdf170f17 --- /dev/null +++ b/src/mbgl/style/function/categorical_stops.cpp @@ -0,0 +1,35 @@ +#include <mbgl/style/function/categorical_stops.hpp> +#include <mbgl/util/color.hpp> + +#include <array> + +namespace mbgl { +namespace style { + +optional<CategoricalValue> categoricalValue(const Value& value) { + return value.match( + [] (bool t) { return optional<CategoricalValue>(t); }, + [] (uint64_t t) { return optional<CategoricalValue>(int64_t(t)); }, + [] (int64_t t) { return optional<CategoricalValue>(t); }, + [] (double t) { return optional<CategoricalValue>(int64_t(t)); }, + [] (const std::string& t) { return optional<CategoricalValue>(t); }, + [] (const auto&) { return optional<CategoricalValue>(); } + ); +} + +template <class T> +T CategoricalStops<T>::evaluate(const Value& value) const { + auto v = categoricalValue(value); + if (!v) { + return defaultValue; + } + auto it = stops.find(*v); + return it == stops.end() ? defaultValue : it->second; +} + +template class CategoricalStops<float>; +template class CategoricalStops<Color>; +template class CategoricalStops<std::array<float, 2>>; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/function/identity_stops.cpp b/src/mbgl/style/function/identity_stops.cpp new file mode 100644 index 0000000000..e210b4d773 --- /dev/null +++ b/src/mbgl/style/function/identity_stops.cpp @@ -0,0 +1,43 @@ +#include <mbgl/style/function/identity_stops.hpp> +#include <mbgl/util/color.hpp> + +#include <array> + +namespace mbgl { +namespace style { + +template <> +float IdentityStops<float>::evaluate(const Value& value) const { + return numericValue<float>(value) + .value_or(0.0f); +} + +template <> +Color IdentityStops<Color>::evaluate(const Value& value) const { + if (!value.is<std::string>()) { + return Color::black(); + } + + return Color::parse(value.get<std::string>()) + .value_or(Color::black()); +} + +template <> +std::array<float, 2> IdentityStops<std::array<float, 2>>::evaluate(const Value& value) const { + if (!value.is<std::vector<Value>>()) { + return {{ 0, 0 }}; + } + + const std::vector<Value>& vector = value.get<std::vector<Value>>(); + if (vector.size() != 2 || !numericValue<float>(vector[0]) || !numericValue<float>(vector[1])) { + return {{ 0, 0 }}; + } + + return {{ + *numericValue<float>(vector[0]), + *numericValue<float>(vector[1]) + }}; +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layer_impl.hpp b/src/mbgl/style/layer_impl.hpp index 0fea70c10b..9b2bfe4d2c 100644 --- a/src/mbgl/style/layer_impl.hpp +++ b/src/mbgl/style/layer_impl.hpp @@ -61,7 +61,7 @@ public: // Returns true if any paint properties have active transitions. virtual bool evaluate(const PropertyEvaluationParameters&) = 0; - virtual std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const = 0; + virtual std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const = 0; // Checks whether this layer needs to be rendered in the given render pass. bool hasRenderPass(RenderPass) const; diff --git a/src/mbgl/style/layer_observer.hpp b/src/mbgl/style/layer_observer.hpp index a3f9ca7528..2fa1c39660 100644 --- a/src/mbgl/style/layer_observer.hpp +++ b/src/mbgl/style/layer_observer.hpp @@ -12,6 +12,7 @@ public: virtual void onLayerFilterChanged(Layer&) {} virtual void onLayerVisibilityChanged(Layer&) {} virtual void onLayerPaintPropertyChanged(Layer&) {} + virtual void onLayerDataDrivenPaintPropertyChanged(Layer&) {} virtual void onLayerLayoutPropertyChanged(Layer&, const char *) {} }; diff --git a/src/mbgl/style/layers/background_layer_impl.cpp b/src/mbgl/style/layers/background_layer_impl.cpp index 4a8fe39c9a..f25ba9cfb4 100644 --- a/src/mbgl/style/layers/background_layer_impl.cpp +++ b/src/mbgl/style/layers/background_layer_impl.cpp @@ -16,7 +16,8 @@ bool BackgroundLayer::Impl::evaluate(const PropertyEvaluationParameters& paramet return paint.hasTransition(); } -std::unique_ptr<Bucket> BackgroundLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const { +std::unique_ptr<Bucket> BackgroundLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const { + assert(false); return nullptr; } diff --git a/src/mbgl/style/layers/background_layer_impl.hpp b/src/mbgl/style/layers/background_layer_impl.hpp index 4629217e6d..02a8c423d6 100644 --- a/src/mbgl/style/layers/background_layer_impl.hpp +++ b/src/mbgl/style/layers/background_layer_impl.hpp @@ -16,7 +16,7 @@ public: void cascade(const CascadeParameters&) override; bool evaluate(const PropertyEvaluationParameters&) override; - std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override; + std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override; BackgroundPaintProperties paint; }; diff --git a/src/mbgl/style/layers/background_layer_properties.hpp b/src/mbgl/style/layers/background_layer_properties.hpp index 792bf3de94..fae6c26a4b 100644 --- a/src/mbgl/style/layers/background_layer_properties.hpp +++ b/src/mbgl/style/layers/background_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/programs/attributes.hpp> namespace mbgl { namespace style { diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index 389ab93403..f8d06e2644 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -65,64 +65,80 @@ const Filter& CircleLayer::getFilter() const { // Paint properties -PropertyValue<float> CircleLayer::getDefaultCircleRadius() { +DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleRadius() { return { 5 }; } -PropertyValue<float> CircleLayer::getCircleRadius(const optional<std::string>& klass) const { +DataDrivenPropertyValue<float> CircleLayer::getCircleRadius(const optional<std::string>& klass) const { return impl->paint.get<CircleRadius>(klass); } -void CircleLayer::setCircleRadius(PropertyValue<float> value, const optional<std::string>& klass) { +void CircleLayer::setCircleRadius(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { if (value == getCircleRadius(klass)) return; impl->paint.set<CircleRadius>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } -PropertyValue<Color> CircleLayer::getDefaultCircleColor() { +DataDrivenPropertyValue<Color> CircleLayer::getDefaultCircleColor() { return { Color::black() }; } -PropertyValue<Color> CircleLayer::getCircleColor(const optional<std::string>& klass) const { +DataDrivenPropertyValue<Color> CircleLayer::getCircleColor(const optional<std::string>& klass) const { return impl->paint.get<CircleColor>(klass); } -void CircleLayer::setCircleColor(PropertyValue<Color> value, const optional<std::string>& klass) { +void CircleLayer::setCircleColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { if (value == getCircleColor(klass)) return; impl->paint.set<CircleColor>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } -PropertyValue<float> CircleLayer::getDefaultCircleBlur() { +DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleBlur() { return { 0 }; } -PropertyValue<float> CircleLayer::getCircleBlur(const optional<std::string>& klass) const { +DataDrivenPropertyValue<float> CircleLayer::getCircleBlur(const optional<std::string>& klass) const { return impl->paint.get<CircleBlur>(klass); } -void CircleLayer::setCircleBlur(PropertyValue<float> value, const optional<std::string>& klass) { +void CircleLayer::setCircleBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { if (value == getCircleBlur(klass)) return; impl->paint.set<CircleBlur>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } -PropertyValue<float> CircleLayer::getDefaultCircleOpacity() { +DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleOpacity() { return { 1 }; } -PropertyValue<float> CircleLayer::getCircleOpacity(const optional<std::string>& klass) const { +DataDrivenPropertyValue<float> CircleLayer::getCircleOpacity(const optional<std::string>& klass) const { return impl->paint.get<CircleOpacity>(klass); } -void CircleLayer::setCircleOpacity(PropertyValue<float> value, const optional<std::string>& klass) { +void CircleLayer::setCircleOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { if (value == getCircleOpacity(klass)) return; impl->paint.set<CircleOpacity>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } PropertyValue<std::array<float, 2>> CircleLayer::getDefaultCircleTranslate() { @@ -170,49 +186,61 @@ void CircleLayer::setCirclePitchScale(PropertyValue<CirclePitchScaleType> value, impl->observer->onLayerPaintPropertyChanged(*this); } -PropertyValue<float> CircleLayer::getDefaultCircleStrokeWidth() { +DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleStrokeWidth() { return { 0 }; } -PropertyValue<float> CircleLayer::getCircleStrokeWidth(const optional<std::string>& klass) const { +DataDrivenPropertyValue<float> CircleLayer::getCircleStrokeWidth(const optional<std::string>& klass) const { return impl->paint.get<CircleStrokeWidth>(klass); } -void CircleLayer::setCircleStrokeWidth(PropertyValue<float> value, const optional<std::string>& klass) { +void CircleLayer::setCircleStrokeWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { if (value == getCircleStrokeWidth(klass)) return; impl->paint.set<CircleStrokeWidth>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } -PropertyValue<Color> CircleLayer::getDefaultCircleStrokeColor() { +DataDrivenPropertyValue<Color> CircleLayer::getDefaultCircleStrokeColor() { return { Color::black() }; } -PropertyValue<Color> CircleLayer::getCircleStrokeColor(const optional<std::string>& klass) const { +DataDrivenPropertyValue<Color> CircleLayer::getCircleStrokeColor(const optional<std::string>& klass) const { return impl->paint.get<CircleStrokeColor>(klass); } -void CircleLayer::setCircleStrokeColor(PropertyValue<Color> value, const optional<std::string>& klass) { +void CircleLayer::setCircleStrokeColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { if (value == getCircleStrokeColor(klass)) return; impl->paint.set<CircleStrokeColor>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } -PropertyValue<float> CircleLayer::getDefaultCircleStrokeOpacity() { +DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleStrokeOpacity() { return { 1 }; } -PropertyValue<float> CircleLayer::getCircleStrokeOpacity(const optional<std::string>& klass) const { +DataDrivenPropertyValue<float> CircleLayer::getCircleStrokeOpacity(const optional<std::string>& klass) const { return impl->paint.get<CircleStrokeOpacity>(klass); } -void CircleLayer::setCircleStrokeOpacity(PropertyValue<float> value, const optional<std::string>& klass) { +void CircleLayer::setCircleStrokeOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { if (value == getCircleStrokeOpacity(klass)) return; impl->paint.set<CircleStrokeOpacity>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } } // namespace style diff --git a/src/mbgl/style/layers/circle_layer_impl.cpp b/src/mbgl/style/layers/circle_layer_impl.cpp index 136522e41c..655ad9b5b9 100644 --- a/src/mbgl/style/layers/circle_layer_impl.cpp +++ b/src/mbgl/style/layers/circle_layer_impl.cpp @@ -1,5 +1,4 @@ #include <mbgl/style/layers/circle_layer_impl.hpp> -#include <mbgl/style/bucket_parameters.hpp> #include <mbgl/renderer/circle_bucket.hpp> #include <mbgl/geometry/feature_index.hpp> #include <mbgl/util/math.hpp> @@ -15,27 +14,22 @@ void CircleLayer::Impl::cascade(const CascadeParameters& parameters) { bool CircleLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) { paint.evaluate(parameters); - passes = (paint.evaluated.get<CircleRadius>() > 0 && paint.evaluated.get<CircleColor>().a > 0 && paint.evaluated.get<CircleOpacity>() > 0) + passes = (paint.evaluated.get<CircleRadius>().constantOr(1) > 0 + && paint.evaluated.get<CircleColor>().constantOr(Color::black()).a > 0 + && paint.evaluated.get<CircleOpacity>().constantOr(1) > 0) ? RenderPass::Translucent : RenderPass::None; return paint.hasTransition(); } -std::unique_ptr<Bucket> CircleLayer::Impl::createBucket(BucketParameters& parameters, const GeometryTileLayer& layer) const { - auto bucket = std::make_unique<CircleBucket>(parameters.mode); - - parameters.eachFilteredFeature(filter, layer, [&] (const auto& feature, std::size_t index, const std::string& layerName) { - auto geometries = feature.getGeometries(); - bucket->addGeometry(geometries); - parameters.featureIndex.insert(geometries, index, layerName, id); - }); - - return std::move(bucket); +std::unique_ptr<Bucket> CircleLayer::Impl::createBucket(const BucketParameters& parameters, const std::vector<const Layer*>& layers) const { + return std::make_unique<CircleBucket>(parameters, layers); } float CircleLayer::Impl::getQueryRadius() const { const std::array<float, 2>& translate = paint.evaluated.get<CircleTranslate>(); - return paint.evaluated.get<CircleRadius>() + util::length(translate[0], translate[1]); + return paint.evaluated.get<CircleRadius>().constantOr(CircleRadius::defaultValue()) + + util::length(translate[0], translate[1]); } bool CircleLayer::Impl::queryIntersectsGeometry( @@ -47,7 +41,7 @@ bool CircleLayer::Impl::queryIntersectsGeometry( auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry( queryGeometry, paint.evaluated.get<CircleTranslate>(), paint.evaluated.get<CircleTranslateAnchor>(), bearing, pixelsToTileUnits); - auto circleRadius = paint.evaluated.get<CircleRadius>() * pixelsToTileUnits; + auto circleRadius = paint.evaluated.get<CircleRadius>().constantOr(CircleRadius::defaultValue()) * pixelsToTileUnits; return util::polygonIntersectsBufferedMultiPoint( translatedQueryGeometry.value_or(queryGeometry), geometry, circleRadius); diff --git a/src/mbgl/style/layers/circle_layer_impl.hpp b/src/mbgl/style/layers/circle_layer_impl.hpp index 744a56898c..0f9611d589 100644 --- a/src/mbgl/style/layers/circle_layer_impl.hpp +++ b/src/mbgl/style/layers/circle_layer_impl.hpp @@ -16,7 +16,7 @@ public: void cascade(const CascadeParameters&) override; bool evaluate(const PropertyEvaluationParameters&) override; - std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override; + std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override; float getQueryRadius() const override; bool queryIntersectsGeometry( diff --git a/src/mbgl/style/layers/circle_layer_properties.hpp b/src/mbgl/style/layers/circle_layer_properties.hpp index ea36b31949..1cb4f5a635 100644 --- a/src/mbgl/style/layers/circle_layer_properties.hpp +++ b/src/mbgl/style/layers/circle_layer_properties.hpp @@ -5,23 +5,24 @@ #include <mbgl/style/types.hpp> #include <mbgl/style/layout_property.hpp> #include <mbgl/style/paint_property.hpp> +#include <mbgl/programs/attributes.hpp> namespace mbgl { namespace style { -struct CircleRadius : PaintProperty<float> { +struct CircleRadius : DataDrivenPaintProperty<float, attributes::a_radius> { static float defaultValue() { return 5; } }; -struct CircleColor : PaintProperty<Color> { +struct CircleColor : DataDrivenPaintProperty<Color, attributes::a_color> { static Color defaultValue() { return Color::black(); } }; -struct CircleBlur : PaintProperty<float> { +struct CircleBlur : DataDrivenPaintProperty<float, attributes::a_blur> { static float defaultValue() { return 0; } }; -struct CircleOpacity : PaintProperty<float> { +struct CircleOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> { static float defaultValue() { return 1; } }; @@ -37,15 +38,15 @@ struct CirclePitchScale : PaintProperty<CirclePitchScaleType> { static CirclePitchScaleType defaultValue() { return CirclePitchScaleType::Map; } }; -struct CircleStrokeWidth : PaintProperty<float> { +struct CircleStrokeWidth : DataDrivenPaintProperty<float, attributes::a_stroke_width> { static float defaultValue() { return 0; } }; -struct CircleStrokeColor : PaintProperty<Color> { +struct CircleStrokeColor : DataDrivenPaintProperty<Color, attributes::a_stroke_color> { static Color defaultValue() { return Color::black(); } }; -struct CircleStrokeOpacity : PaintProperty<float> { +struct CircleStrokeOpacity : DataDrivenPaintProperty<float, attributes::a_stroke_opacity> { static float defaultValue() { return 1; } }; diff --git a/src/mbgl/style/layers/custom_layer_impl.cpp b/src/mbgl/style/layers/custom_layer_impl.cpp index cecd60a296..379de25e8f 100644 --- a/src/mbgl/style/layers/custom_layer_impl.cpp +++ b/src/mbgl/style/layers/custom_layer_impl.cpp @@ -70,7 +70,8 @@ bool CustomLayer::Impl::evaluate(const PropertyEvaluationParameters&) { return false; } -std::unique_ptr<Bucket> CustomLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const { +std::unique_ptr<Bucket> CustomLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const { + assert(false); return nullptr; } diff --git a/src/mbgl/style/layers/custom_layer_impl.hpp b/src/mbgl/style/layers/custom_layer_impl.hpp index 71fb46d0d9..33eb86828c 100644 --- a/src/mbgl/style/layers/custom_layer_impl.hpp +++ b/src/mbgl/style/layers/custom_layer_impl.hpp @@ -32,7 +32,7 @@ private: void cascade(const CascadeParameters&) final {} bool evaluate(const PropertyEvaluationParameters&) final; - std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const final; + std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const final; CustomLayerInitializeFunction initializeFn = nullptr; CustomLayerRenderFunction renderFn = nullptr; diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp index 34f0267d16..0ef5c9bcbc 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp @@ -80,19 +80,23 @@ void FillExtrusionLayer::setFillExtrusionOpacity(PropertyValue<float> value, con impl->observer->onLayerPaintPropertyChanged(*this); } -PropertyValue<Color> FillExtrusionLayer::getDefaultFillExtrusionColor() { +DataDrivenPropertyValue<Color> FillExtrusionLayer::getDefaultFillExtrusionColor() { return { Color::black() }; } -PropertyValue<Color> FillExtrusionLayer::getFillExtrusionColor(const optional<std::string>& klass) const { +DataDrivenPropertyValue<Color> FillExtrusionLayer::getFillExtrusionColor(const optional<std::string>& klass) const { return impl->paint.get<FillExtrusionColor>(klass); } -void FillExtrusionLayer::setFillExtrusionColor(PropertyValue<Color> value, const optional<std::string>& klass) { +void FillExtrusionLayer::setFillExtrusionColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { if (value == getFillExtrusionColor(klass)) return; impl->paint.set<FillExtrusionColor>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } PropertyValue<std::array<float, 2>> FillExtrusionLayer::getDefaultFillExtrusionTranslate() { @@ -140,34 +144,42 @@ void FillExtrusionLayer::setFillExtrusionPattern(PropertyValue<std::string> valu impl->observer->onLayerPaintPropertyChanged(*this); } -PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionHeight() { +DataDrivenPropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionHeight() { return { 0 }; } -PropertyValue<float> FillExtrusionLayer::getFillExtrusionHeight(const optional<std::string>& klass) const { +DataDrivenPropertyValue<float> FillExtrusionLayer::getFillExtrusionHeight(const optional<std::string>& klass) const { return impl->paint.get<FillExtrusionHeight>(klass); } -void FillExtrusionLayer::setFillExtrusionHeight(PropertyValue<float> value, const optional<std::string>& klass) { +void FillExtrusionLayer::setFillExtrusionHeight(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { if (value == getFillExtrusionHeight(klass)) return; impl->paint.set<FillExtrusionHeight>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } -PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionBase() { +DataDrivenPropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionBase() { return { 0 }; } -PropertyValue<float> FillExtrusionLayer::getFillExtrusionBase(const optional<std::string>& klass) const { +DataDrivenPropertyValue<float> FillExtrusionLayer::getFillExtrusionBase(const optional<std::string>& klass) const { return impl->paint.get<FillExtrusionBase>(klass); } -void FillExtrusionLayer::setFillExtrusionBase(PropertyValue<float> value, const optional<std::string>& klass) { +void FillExtrusionLayer::setFillExtrusionBase(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { if (value == getFillExtrusionBase(klass)) return; impl->paint.set<FillExtrusionBase>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } } // 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 ebe9009312..a809820644 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp @@ -11,7 +11,7 @@ bool FillExtrusionLayer::Impl::evaluate(const PropertyEvaluationParameters&) { return false; } -std::unique_ptr<Bucket> FillExtrusionLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const { +std::unique_ptr<Bucket> FillExtrusionLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const { return nullptr; } diff --git a/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp index 3dd8bb270a..ed7ef747fb 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp +++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp @@ -16,7 +16,7 @@ public: void cascade(const CascadeParameters&) override; bool evaluate(const PropertyEvaluationParameters&) override; - std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override; + std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override; FillExtrusionPaintProperties paint; }; diff --git a/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp b/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp index a2d01199a5..c1dd3b079d 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/programs/attributes.hpp> namespace mbgl { namespace style { @@ -13,7 +14,7 @@ struct FillExtrusionOpacity : PaintProperty<float> { static float defaultValue() { return 1; } }; -struct FillExtrusionColor : PaintProperty<Color> { +struct FillExtrusionColor : DataDrivenPaintProperty<Color, attributes::a_color> { static Color defaultValue() { return Color::black(); } }; @@ -29,11 +30,11 @@ struct FillExtrusionPattern : CrossFadedPaintProperty<std::string> { static std::string defaultValue() { return ""; } }; -struct FillExtrusionHeight : PaintProperty<float> { +struct FillExtrusionHeight : DataDrivenPaintProperty<float, attributes::a_height> { static float defaultValue() { return 0; } }; -struct FillExtrusionBase : PaintProperty<float> { +struct FillExtrusionBase : DataDrivenPaintProperty<float, attributes::a_base> { static float defaultValue() { return 0; } }; diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp index b8fa8cad8b..e1c0d4d243 100644 --- a/src/mbgl/style/layers/fill_layer.cpp +++ b/src/mbgl/style/layers/fill_layer.cpp @@ -80,49 +80,61 @@ void FillLayer::setFillAntialias(PropertyValue<bool> value, const optional<std:: impl->observer->onLayerPaintPropertyChanged(*this); } -PropertyValue<float> FillLayer::getDefaultFillOpacity() { +DataDrivenPropertyValue<float> FillLayer::getDefaultFillOpacity() { return { 1 }; } -PropertyValue<float> FillLayer::getFillOpacity(const optional<std::string>& klass) const { +DataDrivenPropertyValue<float> FillLayer::getFillOpacity(const optional<std::string>& klass) const { return impl->paint.get<FillOpacity>(klass); } -void FillLayer::setFillOpacity(PropertyValue<float> value, const optional<std::string>& klass) { +void FillLayer::setFillOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { if (value == getFillOpacity(klass)) return; impl->paint.set<FillOpacity>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } -PropertyValue<Color> FillLayer::getDefaultFillColor() { +DataDrivenPropertyValue<Color> FillLayer::getDefaultFillColor() { return { Color::black() }; } -PropertyValue<Color> FillLayer::getFillColor(const optional<std::string>& klass) const { +DataDrivenPropertyValue<Color> FillLayer::getFillColor(const optional<std::string>& klass) const { return impl->paint.get<FillColor>(klass); } -void FillLayer::setFillColor(PropertyValue<Color> value, const optional<std::string>& klass) { +void FillLayer::setFillColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { if (value == getFillColor(klass)) return; impl->paint.set<FillColor>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } -PropertyValue<Color> FillLayer::getDefaultFillOutlineColor() { +DataDrivenPropertyValue<Color> FillLayer::getDefaultFillOutlineColor() { return { {} }; } -PropertyValue<Color> FillLayer::getFillOutlineColor(const optional<std::string>& klass) const { +DataDrivenPropertyValue<Color> FillLayer::getFillOutlineColor(const optional<std::string>& klass) const { return impl->paint.get<FillOutlineColor>(klass); } -void FillLayer::setFillOutlineColor(PropertyValue<Color> value, const optional<std::string>& klass) { +void FillLayer::setFillOutlineColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { if (value == getFillOutlineColor(klass)) return; impl->paint.set<FillOutlineColor>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } PropertyValue<std::array<float, 2>> FillLayer::getDefaultFillTranslate() { diff --git a/src/mbgl/style/layers/fill_layer_impl.cpp b/src/mbgl/style/layers/fill_layer_impl.cpp index 1ff26aa003..c7c89f8c20 100644 --- a/src/mbgl/style/layers/fill_layer_impl.cpp +++ b/src/mbgl/style/layers/fill_layer_impl.cpp @@ -1,5 +1,4 @@ #include <mbgl/style/layers/fill_layer_impl.hpp> -#include <mbgl/style/bucket_parameters.hpp> #include <mbgl/renderer/fill_bucket.hpp> #include <mbgl/geometry/feature_index.hpp> #include <mbgl/util/math.hpp> @@ -25,7 +24,9 @@ bool FillLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) { passes |= RenderPass::Translucent; } - if (!paint.evaluated.get<FillPattern>().from.empty() || (paint.evaluated.get<FillColor>().a * paint.evaluated.get<FillOpacity>()) < 1.0f) { + if (!paint.unevaluated.get<FillPattern>().isUndefined() + || paint.evaluated.get<FillColor>().constantOr(Color()).a < 1.0f + || paint.evaluated.get<FillOpacity>().constantOr(0) < 1.0f) { passes |= RenderPass::Translucent; } else { passes |= RenderPass::Opaque; @@ -34,16 +35,8 @@ bool FillLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) { return paint.hasTransition(); } -std::unique_ptr<Bucket> FillLayer::Impl::createBucket(BucketParameters& parameters, const GeometryTileLayer& layer) const { - auto bucket = std::make_unique<FillBucket>(); - - parameters.eachFilteredFeature(filter, layer, [&] (const auto& feature, std::size_t index, const std::string& layerName) { - auto geometries = feature.getGeometries(); - bucket->addGeometry(geometries); - parameters.featureIndex.insert(geometries, index, layerName, id); - }); - - return std::move(bucket); +std::unique_ptr<Bucket> FillLayer::Impl::createBucket(const BucketParameters& parameters, const std::vector<const Layer*>& layers) const { + return std::make_unique<FillBucket>(parameters, layers); } float FillLayer::Impl::getQueryRadius() const { diff --git a/src/mbgl/style/layers/fill_layer_impl.hpp b/src/mbgl/style/layers/fill_layer_impl.hpp index 28e2fa7edc..bd25a8bebf 100644 --- a/src/mbgl/style/layers/fill_layer_impl.hpp +++ b/src/mbgl/style/layers/fill_layer_impl.hpp @@ -16,7 +16,7 @@ public: void cascade(const CascadeParameters&) override; bool evaluate(const PropertyEvaluationParameters&) override; - std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override; + std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override; float getQueryRadius() const override; bool queryIntersectsGeometry( diff --git a/src/mbgl/style/layers/fill_layer_properties.hpp b/src/mbgl/style/layers/fill_layer_properties.hpp index b2d926c31e..f44a18d0e0 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/programs/attributes.hpp> namespace mbgl { namespace style { @@ -13,15 +14,15 @@ struct FillAntialias : PaintProperty<bool> { static bool defaultValue() { return true; } }; -struct FillOpacity : PaintProperty<float> { +struct FillOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> { static float defaultValue() { return 1; } }; -struct FillColor : PaintProperty<Color> { +struct FillColor : DataDrivenPaintProperty<Color, attributes::a_color> { static Color defaultValue() { return Color::black(); } }; -struct FillOutlineColor : PaintProperty<Color> { +struct FillOutlineColor : DataDrivenPaintProperty<Color, attributes::a_outline_color> { static Color defaultValue() { return {}; } }; diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index e730e3a29b..4a91a5c7e3 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -86,15 +86,15 @@ const Filter& <%- camelize(type) %>Layer::getFilter() const { // Layout properties <% for (const property of layoutProperties) { -%> -PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() { +<%- propertyValueType(property) %> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() { return <%- camelize(property.name) %>::defaultValue(); } -PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const { +<%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const { return impl->layout.unevaluated.get<<%- camelize(property.name) %>>(); } -void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value) { +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; @@ -104,19 +104,27 @@ void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue // Paint properties <% for (const property of paintProperties) { %> -PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() { +<%- propertyValueType(property) %> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() { return { <%- defaultValue(property) %> }; } -PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(const optional<std::string>& klass) const { +<%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(const optional<std::string>& klass) const { return impl->paint.get<<%- camelize(property.name) %>>(klass); } -void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value, const optional<std::string>& klass) { +void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> value, const optional<std::string>& klass) { if (value == get<%- camelize(property.name) %>(klass)) return; impl->paint.set<<%- camelize(property.name) %>>(value, klass); +<% if (isDataDriven(property)) { -%> + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } +<% } else { -%> impl->observer->onLayerPaintPropertyChanged(*this); +<% } -%> } <% } -%> diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs index d18ad44efd..2a736ca388 100644 --- a/src/mbgl/style/layers/layer_properties.hpp.ejs +++ b/src/mbgl/style/layers/layer_properties.hpp.ejs @@ -10,22 +10,21 @@ #include <mbgl/style/types.hpp> #include <mbgl/style/layout_property.hpp> #include <mbgl/style/paint_property.hpp> +#include <mbgl/programs/attributes.hpp> namespace mbgl { namespace style { <% for (const property of layoutProperties) { -%> -struct <%- camelize(property.name) %> : LayoutProperty<<%- propertyType(property) %>> { +struct <%- camelize(property.name) %> : <%- layoutPropertyType(property, type) %> { static constexpr const char * key = "<%- property.name %>"; - static <%- propertyType(property) %> defaultValue() { return <%- defaultValue(property) %>; } + static <%- evaluatedType(property) %> defaultValue() { return <%- defaultValue(property) %>; } }; <% } -%> <% for (const property of paintProperties) { -%> -struct <%- camelize(property.name) %> : <% -if (/-pattern$/.test(property.name) || property.name === 'line-dasharray') { -%>CrossFaded<% } -%>PaintProperty<<%- propertyType(property) %>> { - static <%- propertyType(property) %> defaultValue() { return <%- defaultValue(property) %>; } +struct <%- camelize(property.name) %> : <%- paintPropertyType(property, type) %> { + static <%- evaluatedType(property) %> defaultValue() { return <%- defaultValue(property) %>; } }; <% } -%> diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index 7f6c148cd1..fcad1eacb6 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -122,34 +122,42 @@ void LineLayer::setLineRoundLimit(PropertyValue<float> value) { // Paint properties -PropertyValue<float> LineLayer::getDefaultLineOpacity() { +DataDrivenPropertyValue<float> LineLayer::getDefaultLineOpacity() { return { 1 }; } -PropertyValue<float> LineLayer::getLineOpacity(const optional<std::string>& klass) const { +DataDrivenPropertyValue<float> LineLayer::getLineOpacity(const optional<std::string>& klass) const { return impl->paint.get<LineOpacity>(klass); } -void LineLayer::setLineOpacity(PropertyValue<float> value, const optional<std::string>& klass) { +void LineLayer::setLineOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { if (value == getLineOpacity(klass)) return; impl->paint.set<LineOpacity>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } -PropertyValue<Color> LineLayer::getDefaultLineColor() { +DataDrivenPropertyValue<Color> LineLayer::getDefaultLineColor() { return { Color::black() }; } -PropertyValue<Color> LineLayer::getLineColor(const optional<std::string>& klass) const { +DataDrivenPropertyValue<Color> LineLayer::getLineColor(const optional<std::string>& klass) const { return impl->paint.get<LineColor>(klass); } -void LineLayer::setLineColor(PropertyValue<Color> value, const optional<std::string>& klass) { +void LineLayer::setLineColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) { if (value == getLineColor(klass)) return; impl->paint.set<LineColor>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } PropertyValue<std::array<float, 2>> LineLayer::getDefaultLineTranslate() { @@ -197,49 +205,61 @@ void LineLayer::setLineWidth(PropertyValue<float> value, const optional<std::str impl->observer->onLayerPaintPropertyChanged(*this); } -PropertyValue<float> LineLayer::getDefaultLineGapWidth() { +DataDrivenPropertyValue<float> LineLayer::getDefaultLineGapWidth() { return { 0 }; } -PropertyValue<float> LineLayer::getLineGapWidth(const optional<std::string>& klass) const { +DataDrivenPropertyValue<float> LineLayer::getLineGapWidth(const optional<std::string>& klass) const { return impl->paint.get<LineGapWidth>(klass); } -void LineLayer::setLineGapWidth(PropertyValue<float> value, const optional<std::string>& klass) { +void LineLayer::setLineGapWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { if (value == getLineGapWidth(klass)) return; impl->paint.set<LineGapWidth>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } -PropertyValue<float> LineLayer::getDefaultLineOffset() { +DataDrivenPropertyValue<float> LineLayer::getDefaultLineOffset() { return { 0 }; } -PropertyValue<float> LineLayer::getLineOffset(const optional<std::string>& klass) const { +DataDrivenPropertyValue<float> LineLayer::getLineOffset(const optional<std::string>& klass) const { return impl->paint.get<LineOffset>(klass); } -void LineLayer::setLineOffset(PropertyValue<float> value, const optional<std::string>& klass) { +void LineLayer::setLineOffset(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { if (value == getLineOffset(klass)) return; impl->paint.set<LineOffset>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } -PropertyValue<float> LineLayer::getDefaultLineBlur() { +DataDrivenPropertyValue<float> LineLayer::getDefaultLineBlur() { return { 0 }; } -PropertyValue<float> LineLayer::getLineBlur(const optional<std::string>& klass) const { +DataDrivenPropertyValue<float> LineLayer::getLineBlur(const optional<std::string>& klass) const { return impl->paint.get<LineBlur>(klass); } -void LineLayer::setLineBlur(PropertyValue<float> value, const optional<std::string>& klass) { +void LineLayer::setLineBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) { if (value == getLineBlur(klass)) return; impl->paint.set<LineBlur>(value, klass); - impl->observer->onLayerPaintPropertyChanged(*this); + if (value.isDataDriven()) { + impl->observer->onLayerDataDrivenPaintPropertyChanged(*this); + } else { + impl->observer->onLayerPaintPropertyChanged(*this); + } } PropertyValue<std::vector<float>> LineLayer::getDefaultLineDasharray() { diff --git a/src/mbgl/style/layers/line_layer_impl.cpp b/src/mbgl/style/layers/line_layer_impl.cpp index 477579a43c..ef0131e3d5 100644 --- a/src/mbgl/style/layers/line_layer_impl.cpp +++ b/src/mbgl/style/layers/line_layer_impl.cpp @@ -1,5 +1,5 @@ #include <mbgl/style/layers/line_layer_impl.hpp> -#include <mbgl/style/bucket_parameters.hpp> +#include <mbgl/style/property_evaluation_parameters.hpp> #include <mbgl/renderer/line_bucket.hpp> #include <mbgl/geometry/feature_index.hpp> #include <mbgl/util/math.hpp> @@ -20,31 +20,25 @@ bool LineLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) { paint.evaluate(parameters); - passes = (paint.evaluated.get<LineOpacity>() > 0 && paint.evaluated.get<LineColor>().a > 0 && paint.evaluated.get<LineWidth>() > 0) + passes = (paint.evaluated.get<LineOpacity>().constantOr(1.0) > 0 + && paint.evaluated.get<LineColor>().constantOr(Color::black()).a > 0 + && paint.evaluated.get<LineWidth>() > 0) ? RenderPass::Translucent : RenderPass::None; return paint.hasTransition(); } -std::unique_ptr<Bucket> LineLayer::Impl::createBucket(BucketParameters& parameters, const GeometryTileLayer& layer) const { - auto bucket = std::make_unique<LineBucket>(parameters.tileID.overscaleFactor()); - - bucket->layout = layout.evaluate(PropertyEvaluationParameters(parameters.tileID.overscaledZ)); - - parameters.eachFilteredFeature(filter, layer, [&] (const auto& feature, std::size_t index, const std::string& layerName) { - auto geometries = feature.getGeometries(); - bucket->addGeometry(geometries); - parameters.featureIndex.insert(geometries, index, layerName, id); - }); - - return std::move(bucket); +std::unique_ptr<Bucket> LineLayer::Impl::createBucket(const BucketParameters& parameters, const std::vector<const Layer*>& layers) const { + return std::make_unique<LineBucket>(parameters, layers, layout); } float LineLayer::Impl::getLineWidth() const { - if (paint.evaluated.get<LineGapWidth>() > 0) { - return paint.evaluated.get<LineGapWidth>() + 2 * paint.evaluated.get<LineWidth>(); + float lineWidth = paint.evaluated.get<LineWidth>(); + float gapWidth = paint.evaluated.get<LineGapWidth>().constantOr(0); + if (gapWidth) { + return gapWidth + 2 * lineWidth; } else { - return paint.evaluated.get<LineWidth>(); + return lineWidth; } } @@ -80,7 +74,8 @@ optional<GeometryCollection> offsetLine(const GeometryCollection& rings, const d float LineLayer::Impl::getQueryRadius() const { const std::array<float, 2>& translate = paint.evaluated.get<LineTranslate>(); - return getLineWidth() / 2.0 + std::abs(paint.evaluated.get<LineOffset>()) + util::length(translate[0], translate[1]); + auto offset = paint.evaluated.get<LineOffset>().constantOr(LineOffset::defaultValue()); + return getLineWidth() / 2.0 + std::abs(offset) + util::length(translate[0], translate[1]); } bool LineLayer::Impl::queryIntersectsGeometry( @@ -93,7 +88,9 @@ bool LineLayer::Impl::queryIntersectsGeometry( auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry( queryGeometry, paint.evaluated.get<LineTranslate>(), paint.evaluated.get<LineTranslateAnchor>(), bearing, pixelsToTileUnits); - auto offsetGeometry = offsetLine(geometry, paint.evaluated.get<LineOffset>() * pixelsToTileUnits); + + auto offset = paint.evaluated.get<LineOffset>().constantOr(LineOffset::defaultValue()); + auto offsetGeometry = offsetLine(geometry, offset * pixelsToTileUnits); return util::polygonIntersectsBufferedMultiLine( translatedQueryGeometry.value_or(queryGeometry), diff --git a/src/mbgl/style/layers/line_layer_impl.hpp b/src/mbgl/style/layers/line_layer_impl.hpp index 1955c019af..67e793f2ea 100644 --- a/src/mbgl/style/layers/line_layer_impl.hpp +++ b/src/mbgl/style/layers/line_layer_impl.hpp @@ -16,7 +16,7 @@ public: void cascade(const CascadeParameters&) override; bool evaluate(const PropertyEvaluationParameters&) override; - std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override; + std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override; float getQueryRadius() const override; bool queryIntersectsGeometry( diff --git a/src/mbgl/style/layers/line_layer_properties.hpp b/src/mbgl/style/layers/line_layer_properties.hpp index 2ea7f6b125..724026e3a6 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/programs/attributes.hpp> namespace mbgl { namespace style { @@ -29,11 +30,11 @@ struct LineRoundLimit : LayoutProperty<float> { static float defaultValue() { return 1; } }; -struct LineOpacity : PaintProperty<float> { +struct LineOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> { static float defaultValue() { return 1; } }; -struct LineColor : PaintProperty<Color> { +struct LineColor : DataDrivenPaintProperty<Color, attributes::a_color> { static Color defaultValue() { return Color::black(); } }; @@ -49,15 +50,15 @@ struct LineWidth : PaintProperty<float> { static float defaultValue() { return 1; } }; -struct LineGapWidth : PaintProperty<float> { +struct LineGapWidth : DataDrivenPaintProperty<float, attributes::a_gap_width> { static float defaultValue() { return 0; } }; -struct LineOffset : PaintProperty<float> { +struct LineOffset : DataDrivenPaintProperty<float, attributes::a_offset<1>> { static float defaultValue() { return 0; } }; -struct LineBlur : PaintProperty<float> { +struct LineBlur : DataDrivenPaintProperty<float, attributes::a_blur> { static float defaultValue() { return 0; } }; diff --git a/src/mbgl/style/layers/raster_layer_impl.cpp b/src/mbgl/style/layers/raster_layer_impl.cpp index a78614aee9..a667ccb5a8 100644 --- a/src/mbgl/style/layers/raster_layer_impl.cpp +++ b/src/mbgl/style/layers/raster_layer_impl.cpp @@ -16,7 +16,8 @@ bool RasterLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) return paint.hasTransition(); } -std::unique_ptr<Bucket> RasterLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const { +std::unique_ptr<Bucket> RasterLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const { + assert(false); return nullptr; } diff --git a/src/mbgl/style/layers/raster_layer_impl.hpp b/src/mbgl/style/layers/raster_layer_impl.hpp index 8e69c21ca8..42985ce0f1 100644 --- a/src/mbgl/style/layers/raster_layer_impl.hpp +++ b/src/mbgl/style/layers/raster_layer_impl.hpp @@ -16,7 +16,7 @@ public: void cascade(const CascadeParameters&) override; bool evaluate(const PropertyEvaluationParameters&) override; - std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override; + std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override; RasterPaintProperties paint; }; diff --git a/src/mbgl/style/layers/raster_layer_properties.hpp b/src/mbgl/style/layers/raster_layer_properties.hpp index caa6d0c58d..219fe34d8c 100644 --- a/src/mbgl/style/layers/raster_layer_properties.hpp +++ b/src/mbgl/style/layers/raster_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/programs/attributes.hpp> namespace mbgl { namespace style { diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index c9014e7ee7..94c47f48b7 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -217,15 +217,15 @@ void SymbolLayer::setIconImage(PropertyValue<std::string> value) { impl->layout.unevaluated.get<IconImage>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-image"); } -PropertyValue<float> SymbolLayer::getDefaultIconRotate() { +DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconRotate() { return IconRotate::defaultValue(); } -PropertyValue<float> SymbolLayer::getIconRotate() const { +DataDrivenPropertyValue<float> SymbolLayer::getIconRotate() const { return impl->layout.unevaluated.get<IconRotate>(); } -void SymbolLayer::setIconRotate(PropertyValue<float> value) { +void SymbolLayer::setIconRotate(DataDrivenPropertyValue<float> value) { if (value == getIconRotate()) return; impl->layout.unevaluated.get<IconRotate>() = value; @@ -259,15 +259,15 @@ void SymbolLayer::setIconKeepUpright(PropertyValue<bool> value) { impl->layout.unevaluated.get<IconKeepUpright>() = value; impl->observer->onLayerLayoutPropertyChanged(*this, "icon-keep-upright"); } -PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconOffset() { +DataDrivenPropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconOffset() { return IconOffset::defaultValue(); } -PropertyValue<std::array<float, 2>> SymbolLayer::getIconOffset() const { +DataDrivenPropertyValue<std::array<float, 2>> SymbolLayer::getIconOffset() const { return impl->layout.unevaluated.get<IconOffset>(); } -void SymbolLayer::setIconOffset(PropertyValue<std::array<float, 2>> value) { +void SymbolLayer::setIconOffset(DataDrivenPropertyValue<std::array<float, 2>> value) { if (value == getIconOffset()) return; impl->layout.unevaluated.get<IconOffset>() = value; diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp index f058598f5f..32547e465a 100644 --- a/src/mbgl/style/layers/symbol_layer_impl.cpp +++ b/src/mbgl/style/layers/symbol_layer_impl.cpp @@ -1,5 +1,5 @@ #include <mbgl/style/layers/symbol_layer_impl.hpp> -#include <mbgl/style/bucket_parameters.hpp> +#include <mbgl/style/property_evaluation_parameters.hpp> #include <mbgl/layout/symbol_layout.hpp> #include <mbgl/renderer/bucket.hpp> @@ -24,52 +24,17 @@ bool SymbolLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) return paint.hasTransition(); } -std::unique_ptr<Bucket> SymbolLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const { +std::unique_ptr<Bucket> SymbolLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const { assert(false); // Should be calling createLayout() instead. return nullptr; } -std::unique_ptr<SymbolLayout> SymbolLayer::Impl::createLayout(BucketParameters& parameters, - const GeometryTileLayer& layer, - std::vector<std::string> group) const { - PropertyEvaluationParameters p(parameters.tileID.overscaledZ); - SymbolLayoutProperties::Evaluated evaluated = layout.evaluate(p); - - if (evaluated.get<IconRotationAlignment>() == AlignmentType::Auto) { - if (evaluated.get<SymbolPlacement>() == SymbolPlacementType::Line) { - evaluated.get<IconRotationAlignment>() = AlignmentType::Map; - } else { - evaluated.get<IconRotationAlignment>() = AlignmentType::Viewport; - } - } - - if (evaluated.get<TextRotationAlignment>() == AlignmentType::Auto) { - if (evaluated.get<SymbolPlacement>() == SymbolPlacementType::Line) { - evaluated.get<TextRotationAlignment>() = AlignmentType::Map; - } else { - evaluated.get<TextRotationAlignment>() = AlignmentType::Viewport; - } - } - - // If unspecified `text-pitch-alignment` inherits `text-rotation-alignment` - if (evaluated.get<TextPitchAlignment>() == AlignmentType::Auto) { - evaluated.get<TextPitchAlignment>() = evaluated.get<TextRotationAlignment>(); - } - - float textMaxSize = layout.evaluate<TextSize>(PropertyEvaluationParameters(18)); - - evaluated.get<IconSize>() = layout.evaluate<IconSize>(PropertyEvaluationParameters(p.z + 1)); - evaluated.get<TextSize>() = layout.evaluate<TextSize>(PropertyEvaluationParameters(p.z + 1)); - - return std::make_unique<SymbolLayout>(std::move(group), - layer.getName(), - parameters.tileID.overscaleFactor(), - parameters.tileID.overscaledZ, - parameters.mode, +std::unique_ptr<SymbolLayout> SymbolLayer::Impl::createLayout(const BucketParameters& parameters, + const std::vector<const Layer*>& group, + const GeometryTileLayer& layer) const { + return std::make_unique<SymbolLayout>(parameters, + group, layer, - filter, - evaluated, - textMaxSize, *spriteAtlas); } diff --git a/src/mbgl/style/layers/symbol_layer_impl.hpp b/src/mbgl/style/layers/symbol_layer_impl.hpp index db18da07e2..c00c2b0bba 100644 --- a/src/mbgl/style/layers/symbol_layer_impl.hpp +++ b/src/mbgl/style/layers/symbol_layer_impl.hpp @@ -50,9 +50,9 @@ public: void cascade(const CascadeParameters&) override; bool evaluate(const PropertyEvaluationParameters&) override; - std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override; - std::unique_ptr<SymbolLayout> createLayout(BucketParameters&, const GeometryTileLayer&, - std::vector<std::string>) const; + std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override; + std::unique_ptr<SymbolLayout> createLayout(const BucketParameters&, const std::vector<const Layer*>&, + const GeometryTileLayer&) const; SymbolPropertyValues iconPropertyValues(const SymbolLayoutProperties::Evaluated&) const; SymbolPropertyValues textPropertyValues(const SymbolLayoutProperties::Evaluated&) const; diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp index f5fd6ce3df..a447eb7efa 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/programs/attributes.hpp> namespace mbgl { namespace style { @@ -64,7 +65,7 @@ struct IconImage : LayoutProperty<std::string> { static std::string defaultValue() { return ""; } }; -struct IconRotate : LayoutProperty<float> { +struct IconRotate : DataDrivenLayoutProperty<float> { static constexpr const char * key = "icon-rotate"; static float defaultValue() { return 0; } }; @@ -79,7 +80,7 @@ struct IconKeepUpright : LayoutProperty<bool> { static bool defaultValue() { return false; } }; -struct IconOffset : LayoutProperty<std::array<float, 2>> { +struct IconOffset : DataDrivenLayoutProperty<std::array<float, 2>> { static constexpr const char * key = "icon-offset"; static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; } }; diff --git a/src/mbgl/style/layout_property.hpp b/src/mbgl/style/layout_property.hpp index 6ea06ce556..7ce2ecc7b8 100644 --- a/src/mbgl/style/layout_property.hpp +++ b/src/mbgl/style/layout_property.hpp @@ -1,6 +1,9 @@ #pragma once +#include <mbgl/style/property_value.hpp> +#include <mbgl/style/data_driven_property_value.hpp> #include <mbgl/style/property_evaluator.hpp> +#include <mbgl/style/data_driven_property_evaluator.hpp> #include <mbgl/util/indexed_tuple.hpp> namespace mbgl { @@ -11,11 +14,19 @@ class PropertyEvaluationParameters; template <class T> class LayoutProperty { public: - using EvaluatorType = PropertyEvaluator<T>; using UnevaluatedType = PropertyValue<T>; + using EvaluatorType = PropertyEvaluator<T>; using EvaluatedType = T; }; +template <class T> +class DataDrivenLayoutProperty { +public: + using UnevaluatedType = DataDrivenPropertyValue<T>; + using EvaluatorType = DataDrivenPropertyEvaluator<T>; + using EvaluatedType = PossiblyEvaluatedPropertyValue<T>; +}; + template <class... Ps> class LayoutProperties { public: diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp index 7b56f6415d..9031d590fe 100644 --- a/src/mbgl/style/paint_property.hpp +++ b/src/mbgl/style/paint_property.hpp @@ -1,11 +1,15 @@ #pragma once #include <mbgl/style/class_dictionary.hpp> +#include <mbgl/style/property_value.hpp> +#include <mbgl/style/data_driven_property_value.hpp> #include <mbgl/style/property_evaluator.hpp> #include <mbgl/style/cross_faded_property_evaluator.hpp> +#include <mbgl/style/data_driven_property_evaluator.hpp> +#include <mbgl/style/property_evaluation_parameters.hpp> #include <mbgl/style/transition_options.hpp> #include <mbgl/style/cascade_parameters.hpp> -#include <mbgl/style/property_evaluation_parameters.hpp> +#include <mbgl/style/paint_property_binder.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/interpolate.hpp> #include <mbgl/util/indexed_tuple.hpp> @@ -15,17 +19,18 @@ #include <utility> namespace mbgl { + +class GeometryTileFeature; + namespace style { -template <class T, class Evaluator> +template <class Value> class UnevaluatedPaintProperty { public: - using Result = typename Evaluator::ResultType; - UnevaluatedPaintProperty() = default; - UnevaluatedPaintProperty(PropertyValue<T> value_, - UnevaluatedPaintProperty<T, Evaluator> prior_, + UnevaluatedPaintProperty(Value value_, + UnevaluatedPaintProperty<Value> prior_, TransitionOptions transition, TimePoint now) : begin(now + transition.delay.value_or(Duration::zero())), @@ -36,22 +41,23 @@ public: } } - Result evaluate(const PropertyEvaluationParameters& parameters, T defaultValue) { - Result finalValue = value.evaluate(Evaluator(parameters, defaultValue)); + template <class Evaluator> + auto evaluate(const Evaluator& evaluator, TimePoint now) { + auto finalValue = value.evaluate(evaluator); if (!prior) { // No prior value. return finalValue; - } else if (parameters.now >= end) { + } else if (now >= end) { // Transition from prior value is now complete. prior = {}; return finalValue; - } else if (parameters.now < begin) { + } else if (now < begin) { // Transition hasn't started yet. - return prior->get().evaluate(parameters, defaultValue); + return prior->get().evaluate(evaluator, now); } else { // Interpolate between recursively-calculated prior value and final. - float t = std::chrono::duration<float>(parameters.now - begin) / (end - begin); - return util::interpolate(prior->get().evaluate(parameters, defaultValue), finalValue, util::DEFAULT_TRANSITION_EASE.solve(t, 0.001)); + 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)); } } @@ -63,27 +69,31 @@ public: return value.isUndefined(); } + const Value& getValue() const { + return value; + } + private: - optional<mapbox::util::recursive_wrapper<UnevaluatedPaintProperty<T, Evaluator>>> prior; + optional<mapbox::util::recursive_wrapper<UnevaluatedPaintProperty<Value>>> prior; TimePoint begin; TimePoint end; - PropertyValue<T> value; + Value value; }; -template <class T> +template <class Value> class CascadingPaintProperty { public: bool isUndefined() const { return values.find(ClassID::Default) == values.end(); } - const PropertyValue<T>& get(const optional<std::string>& klass) const { - static const PropertyValue<T> staticValue; + 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 PropertyValue<T>& value_, const optional<std::string>& klass) { + void set(const Value& value_, const optional<std::string>& klass) { values[klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default] = value_; } @@ -94,7 +104,7 @@ public: template <class UnevaluatedPaintProperty> UnevaluatedPaintProperty cascade(const CascadeParameters& params, UnevaluatedPaintProperty prior) const { TransitionOptions transition; - PropertyValue<T> value; + Value value; for (const auto classID : params.classes) { if (values.find(classID) != values.end()) { @@ -117,7 +127,7 @@ public: } private: - std::unordered_map<ClassID, PropertyValue<T>> values; + std::unordered_map<ClassID, Value> values; std::unordered_map<ClassID, TransitionOptions> transitions; }; @@ -125,26 +135,48 @@ template <class T> class PaintProperty { public: using ValueType = PropertyValue<T>; - using CascadingType = CascadingPaintProperty<T>; + using CascadingType = CascadingPaintProperty<ValueType>; + using UnevaluatedType = UnevaluatedPaintProperty<ValueType>; using EvaluatorType = PropertyEvaluator<T>; - using UnevaluatedType = UnevaluatedPaintProperty<T, EvaluatorType>; using EvaluatedType = T; + static constexpr bool IsDataDriven = false; +}; + +template <class T, class A> +class DataDrivenPaintProperty { +public: + using ValueType = DataDrivenPropertyValue<T>; + using CascadingType = CascadingPaintProperty<ValueType>; + using UnevaluatedType = UnevaluatedPaintProperty<ValueType>; + using EvaluatorType = DataDrivenPropertyEvaluator<T>; + using EvaluatedType = PossiblyEvaluatedPropertyValue<T>; + static constexpr bool IsDataDriven = true; + + using Type = T; + using Attribute = A; }; template <class T> class CrossFadedPaintProperty { public: using ValueType = PropertyValue<T>; - using CascadingType = CascadingPaintProperty<T>; + using CascadingType = CascadingPaintProperty<ValueType>; + using UnevaluatedType = UnevaluatedPaintProperty<ValueType>; using EvaluatorType = CrossFadedPropertyEvaluator<T>; - using UnevaluatedType = UnevaluatedPaintProperty<T, EvaluatorType>; using EvaluatedType = Faded<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...>; @@ -186,7 +218,9 @@ public: template <class P> auto evaluate(const PropertyEvaluationParameters& parameters) { - return unevaluated.template get<P>().evaluate(parameters, P::defaultValue()); + using Evaluator = typename P::EvaluatorType; + return unevaluated.template get<P>() + .evaluate(Evaluator(parameters, P::defaultValue()), parameters.now); } void evaluate(const PropertyEvaluationParameters& parameters) { diff --git a/src/mbgl/style/paint_property_binder.hpp b/src/mbgl/style/paint_property_binder.hpp new file mode 100644 index 0000000000..964f33d2ec --- /dev/null +++ b/src/mbgl/style/paint_property_binder.hpp @@ -0,0 +1,283 @@ +#pragma once + +#include <mbgl/programs/attributes.hpp> +#include <mbgl/gl/attribute.hpp> +#include <mbgl/gl/uniform.hpp> +#include <mbgl/util/type_list.hpp> + +namespace mbgl { +namespace style { + +template <class T, class A> +class ConstantPaintPropertyBinder { +public: + using Attribute = A; + using AttributeValue = typename Attribute::Value; + using AttributeBinding = typename Attribute::Binding; + + ConstantPaintPropertyBinder(T constant_) + : constant(std::move(constant_)) { + } + + void populateVertexVector(const GeometryTileFeature&, std::size_t) {} + void upload(gl::Context&) {} + + AttributeBinding minAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const { + return typename Attribute::ConstantBinding { + Attribute::value(currentValue.constantOr(constant)) + }; + } + + AttributeBinding maxAttributeBinding(const PossiblyEvaluatedPropertyValue<T>&) const { + return AttributeBinding(); + } + + float interpolationFactor(float) const { + return 0.0f; + } + +private: + T constant; +}; + +template <class T, class A> +class SourceFunctionPaintPropertyBinder { +public: + using Attribute = A; + using AttributeValue = typename Attribute::Value; + using AttributeBinding = typename Attribute::Binding; + + using Attributes = gl::Attributes<Attribute>; + using Vertex = typename Attributes::Vertex; + + SourceFunctionPaintPropertyBinder(SourceFunction<T> function_) + : function(std::move(function_)) { + } + + void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) { + AttributeValue value = Attribute::value(function.evaluate(feature)); + for (std::size_t i = vertexVector.vertexSize(); i < length; ++i) { + vertexVector.emplace_back(Vertex { value }); + } + } + + void upload(gl::Context& context) { + vertexBuffer = context.createVertexBuffer(std::move(vertexVector)); + } + + AttributeBinding minAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const { + if (currentValue.isConstant()) { + return typename Attribute::ConstantBinding { + Attribute::value(*currentValue.constant()) + }; + } else { + return Attributes::allVariableBindings(*vertexBuffer) + .template get<Attribute>(); + } + } + + AttributeBinding maxAttributeBinding(const PossiblyEvaluatedPropertyValue<T>&) const { + return AttributeBinding(); + } + + float interpolationFactor(float) const { + return 0.0f; + } + +private: + SourceFunction<T> function; + gl::VertexVector<Vertex> vertexVector; + optional<gl::VertexBuffer<Vertex>> vertexBuffer; +}; + +template <class T, class A> +class CompositeFunctionPaintPropertyBinder { +public: + using Attribute = A; + using AttributeValue = typename Attribute::Value; + using AttributeBinding = typename Attribute::Binding; + + using MinAttribute = attributes::Min<Attribute>; + using MaxAttribute = attributes::Max<Attribute>; + + using Attributes = gl::Attributes<MinAttribute, MaxAttribute>; + using Vertex = typename Attributes::Vertex; + + CompositeFunctionPaintPropertyBinder(CompositeFunction<T> function_, float zoom) + : function(std::move(function_)), + coveringRanges(function.coveringRanges(zoom)) { + } + + void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) { + Range<T> range = function.evaluate(std::get<1>(coveringRanges), feature); + AttributeValue min = Attribute::value(range.min); + AttributeValue max = Attribute::value(range.max); + for (std::size_t i = vertexVector.vertexSize(); i < length; ++i) { + vertexVector.emplace_back(Vertex { min, max }); + } + } + + void upload(gl::Context& context) { + vertexBuffer = context.createVertexBuffer(std::move(vertexVector)); + } + + AttributeBinding minAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const { + if (currentValue.isConstant()) { + return typename Attribute::ConstantBinding { + Attribute::value(*currentValue.constant()) + }; + } else { + return Attributes::allVariableBindings(*vertexBuffer) + .template get<MinAttribute>(); + } + } + + AttributeBinding maxAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const { + if (currentValue.isConstant()) { + return AttributeBinding(); + } else { + return Attributes::allVariableBindings(*vertexBuffer) + .template get<MaxAttribute>(); + } + } + + float interpolationFactor(float currentZoom) const { + return util::interpolationFactor(1.0f, std::get<0>(coveringRanges), currentZoom); + } + +private: + using InnerStops = typename CompositeFunction<T>::InnerStops; + CompositeFunction<T> function; + std::tuple<Range<float>, Range<InnerStops>> coveringRanges; + gl::VertexVector<Vertex> vertexVector; + optional<gl::VertexBuffer<Vertex>> vertexBuffer; +}; + +template <class PaintProperty> +class PaintPropertyBinder { +public: + using Type = typename PaintProperty::Type; + using Attribute = typename PaintProperty::Attribute; + using PropertyValue = typename PaintProperty::EvaluatedType; + + using Binder = variant< + ConstantPaintPropertyBinder<Type, Attribute>, + SourceFunctionPaintPropertyBinder<Type, Attribute>, + CompositeFunctionPaintPropertyBinder<Type, Attribute>>; + + PaintPropertyBinder(const PropertyValue& value, float zoom) + : binder(value.match( + [&] (const Type& constant) -> Binder { + return ConstantPaintPropertyBinder<Type, Attribute>(constant); + }, + [&] (const SourceFunction<Type>& function) { + return SourceFunctionPaintPropertyBinder<Type, Attribute>(function); + }, + [&] (const CompositeFunction<Type>& function) { + return CompositeFunctionPaintPropertyBinder<Type, Attribute>(function, zoom); + } + )) { + } + + void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) { + binder.match([&] (auto& b) { + b.populateVertexVector(feature, length); + }); + } + + void upload(gl::Context& context) { + binder.match([&] (auto& b) { + b.upload(context); + }); + } + + using MinAttribute = attributes::Min<Attribute>; + using MaxAttribute = attributes::Max<Attribute>; + using AttributeBinding = typename Attribute::Binding; + + AttributeBinding minAttributeBinding(const PropertyValue& currentValue) const { + return binder.match([&] (const auto& b) { + return b.minAttributeBinding(currentValue); + }); + } + + AttributeBinding maxAttributeBinding(const PropertyValue& currentValue) const { + return binder.match([&] (const auto& b) { + return b.maxAttributeBinding(currentValue); + }); + } + + using InterpolationUniform = attributes::InterpolationUniform<Attribute>; + using InterpolationUniformValue = typename InterpolationUniform::Value; + + InterpolationUniformValue interpolationUniformValue(float currentZoom) const { + return InterpolationUniformValue { + binder.match([&] (const auto& b) { + return b.interpolationFactor(currentZoom); + }) + }; + } + +private: + Binder binder; +}; + +template <class Ps> +class PaintPropertyBinders; + +template <class... Ps> +class PaintPropertyBinders<TypeList<Ps...>> { +public: + using Binders = IndexedTuple<TypeList<Ps...>, TypeList<PaintPropertyBinder<Ps>...>>; + + template <class EvaluatedProperties> + PaintPropertyBinders(const EvaluatedProperties& properties, float z) + : binders(PaintPropertyBinder<Ps>(properties.template get<Ps>(), z)...) { + (void)z; // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56958 + } + + void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length) { + util::ignore({ + (binders.template get<Ps>().populateVertexVector(feature, length), 0)... + }); + } + + void upload(gl::Context& context) { + util::ignore({ + (binders.template get<Ps>().upload(context), 0)... + }); + } + + using MinAttributes = gl::Attributes<typename PaintPropertyBinder<Ps>::MinAttribute...>; + using MaxAttributes = gl::Attributes<typename PaintPropertyBinder<Ps>::MaxAttribute...>; + + using Attributes = gl::ConcatenateAttributes<MinAttributes, MaxAttributes>; + using AttributeBindings = typename Attributes::Bindings; + + template <class EvaluatedProperties> + AttributeBindings attributeBindings(const EvaluatedProperties& currentProperties) const { + const typename MinAttributes::Bindings min { + binders.template get<Ps>().minAttributeBinding(currentProperties.template get<Ps>())... + }; + const typename MaxAttributes::Bindings max { + binders.template get<Ps>().maxAttributeBinding(currentProperties.template get<Ps>())... + }; + return min.concat(max); + } + + using Uniforms = gl::Uniforms<typename PaintPropertyBinder<Ps>::InterpolationUniform...>; + using UniformValues = typename Uniforms::Values; + + UniformValues uniformValues(float currentZoom) const { + (void)currentZoom; // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56958 + return UniformValues { + binders.template get<Ps>().interpolationUniformValue(currentZoom)... + }; + } + +private: + Binders binders; +}; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp index c6c6e50dd7..926c243733 100644 --- a/src/mbgl/style/parser.cpp +++ b/src/mbgl/style/parser.cpp @@ -241,10 +241,14 @@ std::vector<FontStack> Parser::fontStacks() const { result.insert({"Open Sans Regular", "Arial Unicode MS Regular"}); } else if (textFont.isConstant()) { result.insert(textFont.asConstant()); - } else if (textFont.isFunction()) { - for (const auto& stop : textFont.asFunction().getStops()) { - result.insert(stop.second); - } + } else if (textFont.isCameraFunction()) { + textFont.asCameraFunction().stops.match( + [&] (const auto& stops) { + for (const auto& stop : stops.stops) { + result.insert(stop.second); + } + } + ); } } } diff --git a/src/mbgl/style/possibly_evaluated_property_value.hpp b/src/mbgl/style/possibly_evaluated_property_value.hpp new file mode 100644 index 0000000000..bb917442f6 --- /dev/null +++ b/src/mbgl/style/possibly_evaluated_property_value.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include <mbgl/style/function/source_function.hpp> +#include <mbgl/style/function/composite_function.hpp> +#include <mbgl/util/interpolate.hpp> +#include <mbgl/util/variant.hpp> + +namespace mbgl { + +class GeometryTileFeature; + +namespace style { + +template <class T> +class PossiblyEvaluatedPropertyValue { +private: + using Value = variant< + T, + SourceFunction<T>, + CompositeFunction<T>>; + + Value value; + +public: + PossiblyEvaluatedPropertyValue() = default; + PossiblyEvaluatedPropertyValue(Value v) : value(std::move(v)) {} + + bool isConstant() const { + return value.template is<T>(); + } + + optional<T> constant() const { + return value.match( + [&] (const T& t) { return optional<T>(t); }, + [&] (const auto&) { return optional<T>(); }); + } + + T constantOr(const T& t) const { + return constant().value_or(t); + } + + template <class... Ts> + auto match(Ts&&... ts) const { + return value.match(std::forward<Ts>(ts)...); + } + + T evaluate(float z, const GeometryTileFeature& feature) const { + return value.match( + [&] (const T& t) { return t; }, + [&] (const SourceFunction<T>& t) { return t.evaluate(feature); }, + [&] (const CompositeFunction<T>& t) { return t.evaluate(z, feature); }); + } +}; + +} // namespace style + +namespace util { + +template <typename T> +struct Interpolator<style::PossiblyEvaluatedPropertyValue<T>> { + style::PossiblyEvaluatedPropertyValue<T> operator()(const style::PossiblyEvaluatedPropertyValue<T>& a, + const style::PossiblyEvaluatedPropertyValue<T>& b, + const double t) const { + if (a.isConstant() && b.isConstant()) { + return { interpolate(*a.constant(), *b.constant(), t) }; + } else { + return { a }; + } + } +}; + +} // namespace util + +} // namespace mbgl diff --git a/src/mbgl/style/property_evaluator.hpp b/src/mbgl/style/property_evaluator.hpp index ca4962d948..3f629ada4f 100644 --- a/src/mbgl/style/property_evaluator.hpp +++ b/src/mbgl/style/property_evaluator.hpp @@ -17,7 +17,7 @@ public: T operator()(const Undefined&) const { return defaultValue; } T operator()(const T& constant) const { return constant; } - T operator()(const Function<T>& fn) const { return fn.evaluate(parameters.z); } + T operator()(const CameraFunction<T>& fn) const { return fn.evaluate(parameters.z); } private: const PropertyEvaluationParameters& parameters; diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index d6a525f502..61fbba67b5 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -662,6 +662,11 @@ void Style::onLayerPaintPropertyChanged(Layer&) { observer->onUpdate(Update::RecalculateStyle | Update::Classes); } +void Style::onLayerDataDrivenPaintPropertyChanged(Layer& layer) { + layer.accept(QueueSourceReloadVisitor { updateBatch }); + observer->onUpdate(Update::RecalculateStyle | Update::Classes | Update::Layout); +} + void Style::onLayerLayoutPropertyChanged(Layer& layer, const char * property) { layer.accept(QueueSourceReloadVisitor { updateBatch }); diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index d46e80e8bf..4c4bcec63a 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -146,6 +146,7 @@ private: void onLayerFilterChanged(Layer&) override; void onLayerVisibilityChanged(Layer&) override; void onLayerPaintPropertyChanged(Layer&) override; + void onLayerDataDrivenPaintPropertyChanged(Layer&) override; void onLayerLayoutPropertyChanged(Layer&, const char *) override; Observer nullObserver; |