diff options
author | Molly Lloyd <molly@mapbox.com> | 2018-06-14 14:35:39 -0700 |
---|---|---|
committer | Molly Lloyd <mollymerp@users.noreply.github.com> | 2018-08-31 13:08:47 -0700 |
commit | 4a5dc37245d23805d13865f5ef9c5f26e539a9ca (patch) | |
tree | de77bfeff6f7afbe02210c9189bf72da59293083 /src/mbgl/renderer/paint_property_binder.hpp | |
parent | ec62e321531b1a836074056e86de8e20018280fb (diff) | |
download | qtlocation-mapboxgl-4a5dc37245d23805d13865f5ef9c5f26e539a9ca.tar.gz |
[core] Implement CrossFadedDataDrivenProperty to add support for feature expressions in `*-pattern` properties
Diffstat (limited to 'src/mbgl/renderer/paint_property_binder.hpp')
-rw-r--r-- | src/mbgl/renderer/paint_property_binder.hpp | 314 |
1 files changed, 243 insertions, 71 deletions
diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index 29eb716785..dd204743b3 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -7,6 +7,11 @@ #include <mbgl/util/type_list.hpp> #include <mbgl/renderer/possibly_evaluated_property_value.hpp> #include <mbgl/renderer/paint_property_statistics.hpp> +#include <mbgl/renderer/cross_faded_property_evaluator.hpp> +#include <mbgl/util/variant.hpp> +#include <mbgl/renderer/image_atlas.hpp> +#include <mbgl/util/indexed_tuple.hpp> +#include <mbgl/layout/pattern_layout.hpp> #include <bitset> @@ -72,54 +77,92 @@ std::array<float, N*2> zoomInterpolatedAttributeValue(const std::array<float, N> Note that the shader source varies depending on whether we're using a uniform or attribute. Like GL JS, we dynamically compile shaders at runtime to accomodate this. */ -template <class T, class... As> + +template <class T, class UniformValueType, class PossiblyEvaluatedType, class... As> class PaintPropertyBinder { public: virtual ~PaintPropertyBinder() = default; - virtual void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) = 0; + virtual void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional<PatternDependency>&) = 0; virtual void upload(gl::Context& context) = 0; - virtual optional<gl::AttributeBinding> attributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const = 0; - virtual float interpolationFactor(float currentZoom) const = 0; - virtual T uniformValue(const PossiblyEvaluatedPropertyValue<T>& currentValue) const = 0; + virtual void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, CrossfadeParameters&) = 0; + virtual std::tuple<ExpandToType<As, optional<gl::AttributeBinding>>...> attributeBinding(const PossiblyEvaluatedType& currentValue) const = 0; + virtual std::tuple<ExpandToType<As, float>...> interpolationFactor(float currentZoom) const = 0; + virtual std::tuple<ExpandToType<As, UniformValueType>...> uniformValue(const PossiblyEvaluatedType& currentValue) const = 0; - static std::unique_ptr<PaintPropertyBinder> create(const PossiblyEvaluatedPropertyValue<T>& value, float zoom, T defaultValue); + static std::unique_ptr<PaintPropertyBinder> create(const PossiblyEvaluatedType& value, float zoom, T defaultValue); PaintPropertyStatistics<T> statistics; }; template <class T, class A> -class ConstantPaintPropertyBinder : public PaintPropertyBinder<T, A> { +class ConstantPaintPropertyBinder : public PaintPropertyBinder<T, T, PossiblyEvaluatedPropertyValue<T>, A> { public: ConstantPaintPropertyBinder(T constant_) : constant(std::move(constant_)) { } - void populateVertexVector(const GeometryTileFeature&, std::size_t) override {} + void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional<PatternDependency>&) override {} void upload(gl::Context&) override {} + void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, CrossfadeParameters&) override {}; - optional<gl::AttributeBinding> attributeBinding(const PossiblyEvaluatedPropertyValue<T>&) const override { - return {}; + std::tuple<optional<gl::AttributeBinding>> attributeBinding(const PossiblyEvaluatedPropertyValue<T>&) const override { + return std::tuple<optional<gl::AttributeBinding>> {}; } - float interpolationFactor(float) const override { - return 0.0f; + std::tuple<float> interpolationFactor(float) const override { + return std::tuple<float> { 0.0f }; } - T uniformValue(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { - return currentValue.constantOr(constant); + std::tuple<T> uniformValue(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { + return std::tuple<T> { currentValue.constantOr(constant) }; } private: T constant; }; +template <class T, class... As> +class ConstantCrossFadedPaintPropertyBinder : public PaintPropertyBinder<T, std::array<uint16_t, 4>,PossiblyEvaluatedPropertyValue<Faded<T>>, As...> { +public: + ConstantCrossFadedPaintPropertyBinder(Faded<T> constant_) + : constant(std::move(constant_)), constantPatternPositions({}) { + } + + void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional<PatternDependency>&) override {} + void upload(gl::Context&) override {} + + void setPatternParameters(const optional<ImagePosition>& posA, const optional<ImagePosition>& posB, CrossfadeParameters&) override { + if (!posA && !posB) { + return; + } else { + constantPatternPositions = std::tuple<std::array<uint16_t, 4>, std::array<uint16_t, 4>> { posB->tlbr(), posA->tlbr() }; + } + } + + std::tuple<optional<gl::AttributeBinding>, optional<gl::AttributeBinding>> + attributeBinding(const PossiblyEvaluatedPropertyValue<Faded<T>>&) const override { + return std::tuple<optional<gl::AttributeBinding>, optional<gl::AttributeBinding>> {}; + } + + std::tuple<float, float> interpolationFactor(float) const override { + return std::tuple<float, float> { 0.0f, 0.0f }; + } + + std::tuple<std::array<uint16_t, 4>, std::array<uint16_t, 4>> uniformValue(const PossiblyEvaluatedPropertyValue<Faded<T>>&) const override { + return constantPatternPositions; + } + +private: + Faded<T> constant; + std::tuple<std::array<uint16_t, 4>, std::array<uint16_t, 4>> constantPatternPositions; +}; + template <class T, class A> -class SourceFunctionPaintPropertyBinder : public PaintPropertyBinder<T, A> { +class SourceFunctionPaintPropertyBinder : public PaintPropertyBinder<T, T, PossiblyEvaluatedPropertyValue<T>, A> { public: using BaseAttribute = A; - using BaseAttributeValue = typename BaseAttribute::Value; using BaseVertex = gl::detail::Vertex<BaseAttribute>; using AttributeType = ZoomInterpolatedAttributeType<A>; @@ -128,8 +171,8 @@ public: : expression(std::move(expression_)), defaultValue(std::move(defaultValue_)) { } - - void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) override { + void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, CrossfadeParameters&) override {}; + void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional<PatternDependency>&) override { auto evaluated = expression.evaluate(feature, defaultValue); this->statistics.add(evaluated); auto value = attributeValue(evaluated); @@ -142,21 +185,21 @@ public: vertexBuffer = context.createVertexBuffer(std::move(vertexVector)); } - optional<gl::AttributeBinding> attributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { + std::tuple<optional<gl::AttributeBinding>> attributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { if (currentValue.isConstant()) { return {}; } else { - return AttributeType::binding(*vertexBuffer, 0, BaseAttribute::Dimensions); + return std::tuple<optional<gl::AttributeBinding>> { AttributeType::binding(*vertexBuffer, 0, BaseAttribute::Dimensions) }; } } - float interpolationFactor(float) const override { - return 0.0f; + std::tuple<float> interpolationFactor(float) const override { + return std::tuple<float> { 0.0f }; } - T uniformValue(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { + std::tuple<T> uniformValue(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { if (currentValue.isConstant()) { - return *currentValue.constant(); + return std::tuple<T>{ *currentValue.constant() }; } else { // Uniform values for vertex attribute arrays are unused. return {}; @@ -171,7 +214,7 @@ private: }; template <class T, class A> -class CompositeFunctionPaintPropertyBinder : public PaintPropertyBinder<T, A> { +class CompositeFunctionPaintPropertyBinder : public PaintPropertyBinder<T, T, PossiblyEvaluatedPropertyValue<T>, A> { public: using AttributeType = ZoomInterpolatedAttributeType<A>; @@ -183,8 +226,8 @@ public: defaultValue(std::move(defaultValue_)), zoomRange({zoom, zoom + 1}) { } - - void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) override { + void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, CrossfadeParameters&) override {}; + void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional<PatternDependency>&) override { Range<T> range = expression.evaluate(zoomRange, feature, defaultValue); this->statistics.add(range.min); this->statistics.add(range.max); @@ -200,25 +243,25 @@ public: vertexBuffer = context.createVertexBuffer(std::move(vertexVector)); } - optional<gl::AttributeBinding> attributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { + std::tuple<optional<gl::AttributeBinding>> attributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { if (currentValue.isConstant()) { return {}; } else { - return AttributeType::binding(*vertexBuffer, 0); + return std::tuple<optional<gl::AttributeBinding>> { AttributeType::binding(*vertexBuffer, 0) }; } } - float interpolationFactor(float currentZoom) const override { + std::tuple<float> interpolationFactor(float currentZoom) const override { if (expression.useIntegerZoom) { - return expression.interpolationFactor(zoomRange, std::floor(currentZoom)); + return std::tuple<float> { expression.interpolationFactor(zoomRange, std::floor(currentZoom)) }; } else { - return expression.interpolationFactor(zoomRange, currentZoom); + return std::tuple<float> { expression.interpolationFactor(zoomRange, currentZoom) }; } } - T uniformValue(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { + std::tuple<T> uniformValue(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { if (currentValue.isConstant()) { - return *currentValue.constant(); + return std::tuple<T> { *currentValue.constant() }; } else { // Uniform values for vertex attribute arrays are unused. return {}; @@ -233,21 +276,131 @@ private: optional<gl::VertexBuffer<Vertex>> vertexBuffer; }; -template <class T, class... As> -std::unique_ptr<PaintPropertyBinder<T, As...>> -PaintPropertyBinder<T, As...>::create(const PossiblyEvaluatedPropertyValue<T>& value, float zoom, T defaultValue) { - return value.match( - [&] (const T& constant) -> std::unique_ptr<PaintPropertyBinder<T, As...>> { - return std::make_unique<ConstantPaintPropertyBinder<T, As...>>(constant); - }, - [&] (const style::PropertyExpression<T>& expression) -> std::unique_ptr<PaintPropertyBinder<T, As...>> { - if (expression.isZoomConstant()) { - return std::make_unique<SourceFunctionPaintPropertyBinder<T, As...>>(expression, defaultValue); - } else { - return std::make_unique<CompositeFunctionPaintPropertyBinder<T, As...>>(expression, zoom, defaultValue); +template <class T, class A1, class A2> +class CompositeCrossFadedPaintPropertyBinder : public PaintPropertyBinder<T, std::array<uint16_t, 4>, PossiblyEvaluatedPropertyValue<Faded<T>>, A1, A2> { +public: + using AttributeType = ZoomInterpolatedAttributeType<A1>; + using AttributeType2 = ZoomInterpolatedAttributeType<A2>; + + using BaseAttribute = A1; + using BaseAttributeValue = typename BaseAttribute::Value; + + using BaseAttribute2 = A2; + using BaseAttributeValue2 = typename BaseAttribute2::Value; + + using Vertex = gl::detail::Vertex<BaseAttribute>; + using Vertex2 = gl::detail::Vertex<BaseAttribute2>; + + CompositeCrossFadedPaintPropertyBinder(style::PropertyExpression<T> expression_, float zoom, T defaultValue_) + : expression(std::move(expression_)), + defaultValue(std::move(defaultValue_)), + zoomRange({zoom, zoom + 1}) { + } + + void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, CrossfadeParameters& crossfade_) override { + crossfade = crossfade_; + }; + + void populateVertexVector(const GeometryTileFeature&, std::size_t length, const ImagePositions& patternPositions, const optional<PatternDependency>& patternDependencies) override { + if (!patternDependencies) return; + if (!patternPositions.empty()) { + const auto min = patternPositions.find(patternDependencies->min); + const auto mid = patternPositions.find(patternDependencies->mid); + const auto max = patternPositions.find(patternDependencies->max); + + const auto end = patternPositions.end(); + if (min == end || mid == end || max == end) return; + + const ImagePosition imageMin = min->second; + const ImagePosition imageMid = mid->second; + const ImagePosition imageMax = max->second; + + for (std::size_t i = zoomInVertexVector.vertexSize(); i < length; ++i) { + patternToVertexVector.emplace_back(Vertex { imageMid.tlbr() }); + zoomInVertexVector.emplace_back(Vertex2 { imageMin.tlbr() }); + zoomOutVertexVector.emplace_back(Vertex2 { imageMax.tlbr() }); } } - ); + } + + void upload(gl::Context& context) override { + patternToVertexBuffer = context.createVertexBuffer(std::move(patternToVertexVector)); + zoomInVertexBuffer = context.createVertexBuffer(std::move(zoomInVertexVector)); + zoomOutVertexBuffer = context.createVertexBuffer(std::move(zoomOutVertexVector)); + } + + std::tuple<optional<gl::AttributeBinding>, optional<gl::AttributeBinding>> attributeBinding(const PossiblyEvaluatedPropertyValue<Faded<T>>& currentValue) const override { + if (currentValue.isConstant()) { + return {}; + } else { + return std::tuple<optional<gl::AttributeBinding>, optional<gl::AttributeBinding>> { + AttributeType::binding(*patternToVertexBuffer, 0, BaseAttribute::Dimensions), + AttributeType2::binding( + crossfade.fromScale == 2 ? *zoomInVertexBuffer : *zoomOutVertexBuffer, + 0, BaseAttribute2::Dimensions) }; + } + } + + std::tuple<float, float> interpolationFactor(float) const override { + return std::tuple<float, float> { 0.0f, 0.0f }; + } + + std::tuple<std::array<uint16_t, 4>, std::array<uint16_t, 4>> uniformValue(const PossiblyEvaluatedPropertyValue<Faded<T>>& ) const override { + // Uniform values for vertex attribute arrays are unused. + return {}; + } + +private: + style::PropertyExpression<T> expression; + T defaultValue; + Range<float> zoomRange; + gl::VertexVector<Vertex> patternToVertexVector; + gl::VertexVector<Vertex2> zoomInVertexVector; + gl::VertexVector<Vertex2> zoomOutVertexVector; + optional<gl::VertexBuffer<Vertex>> patternToVertexBuffer; + optional<gl::VertexBuffer<Vertex2>> zoomInVertexBuffer; + optional<gl::VertexBuffer<Vertex2>> zoomOutVertexBuffer; + CrossfadeParameters crossfade; +}; + +template <class T, class PossiblyEvaluatedType> +struct CreateBinder { + template <class A> + static std::unique_ptr<PaintPropertyBinder<T, T, PossiblyEvaluatedType, A>> create(const PossiblyEvaluatedType& value, float zoom, T defaultValue) { + return value.match( + [&] (const T& constant) -> std::unique_ptr<PaintPropertyBinder<T, T, PossiblyEvaluatedType, A>> { + return std::make_unique<ConstantPaintPropertyBinder<T, A>>(constant); + }, + [&] (const style::PropertyExpression<T>& expression) -> std::unique_ptr<PaintPropertyBinder<T, T, PossiblyEvaluatedType, A>> { + if (expression.isZoomConstant()) { + return std::make_unique<SourceFunctionPaintPropertyBinder<T, A>>(expression, defaultValue); + } else { + return std::make_unique<CompositeFunctionPaintPropertyBinder<T, A>>(expression, zoom, defaultValue); + } + } + ); + } +}; + +template <class T> +struct CreateBinder<T, PossiblyEvaluatedPropertyValue<Faded<T>>> { + template <class A1, class A2> + static std::unique_ptr<PaintPropertyBinder<T, std::array<uint16_t, 4>, PossiblyEvaluatedPropertyValue<Faded<T>>, A1, A2>> create(const PossiblyEvaluatedPropertyValue<Faded<T>>& value, float zoom, T defaultValue) { + return value.match( + [&] (const Faded<T>& constant) -> std::unique_ptr<PaintPropertyBinder<T, std::array<uint16_t, 4>, PossiblyEvaluatedPropertyValue<Faded<T>>, A1, A2>> { + return std::make_unique<ConstantCrossFadedPaintPropertyBinder<T, A1, A2>>(constant); + }, + [&] (const style::PropertyExpression<T>& expression) -> std::unique_ptr<PaintPropertyBinder<T, std::array<uint16_t, 4>, PossiblyEvaluatedPropertyValue<Faded<T>>, A1, A2>> { + return std::make_unique<CompositeCrossFadedPaintPropertyBinder<T, A1, A2>>(expression, zoom, defaultValue); + } + ); + } +}; + +template <class T, class UniformValueType, class PossiblyEvaluatedType, class... As> +std::unique_ptr<PaintPropertyBinder<T, UniformValueType, PossiblyEvaluatedType, As... >> +PaintPropertyBinder<T, UniformValueType, PossiblyEvaluatedType, As...>::create(const PossiblyEvaluatedType& value, float zoom, T defaultValue) { + return CreateBinder<T, PossiblyEvaluatedType>::template create<As...>(value, zoom, defaultValue); } template <class Attr> @@ -270,17 +423,18 @@ class PaintPropertyBinders; template <class... Ps> class PaintPropertyBinders<TypeList<Ps...>> { private: - template <class T, class... As> + template <class T, class PossiblyEvaluatedType, class... As> struct Detail; - template <class T, class... As> - struct Detail<T, TypeList<As...>> { - using Binder = PaintPropertyBinder<T, typename As::Type...>; + template <class T, class UniformValueType, class PossiblyEvaluatedType, class... As> + struct Detail<T, UniformValueType, PossiblyEvaluatedType, TypeList<As...>> { + using Binder = PaintPropertyBinder<T, UniformValueType, PossiblyEvaluatedType, typename As::Type...>; using ZoomInterpolatedAttributeList = TypeList<ZoomInterpolatedAttribute<As>...>; + using InterpolationUniformList = TypeList<InterpolationUniform<As>...>; }; template <class P> - using Property = Detail<typename P::Type, typename P::Attributes>; + using Property = Detail<typename P::Type, typename P::Uniform::Type, typename P::PossiblyEvaluatedType, typename P::Attributes>; public: template <class P> @@ -299,9 +453,15 @@ public: PaintPropertyBinders(PaintPropertyBinders&&) = default; PaintPropertyBinders(const PaintPropertyBinders&) = delete; - void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length) { + void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length, const ImagePositions& patternPositions, const optional<PatternDependency>& patternDependencies) { util::ignore({ - (binders.template get<Ps>()->populateVertexVector(feature, length), 0)... + (binders.template get<Ps>()->populateVertexVector(feature, length, patternPositions, patternDependencies), 0)... + }); + } + + void setPatternParameters(const optional<ImagePosition>& posA, const optional<ImagePosition>& posB, CrossfadeParameters& crossfade) const { + util::ignore({ + (binders.template get<Ps>()->setPatternParameters(posA, posB, crossfade), 0)... }); } @@ -313,31 +473,32 @@ public: template <class P> using ZoomInterpolatedAttributeList = typename Property<P>::ZoomInterpolatedAttributeList; + template <class P> + using InterpolationUniformList = typename Property<P>::InterpolationUniformList; using Attributes = typename TypeListConcat<ZoomInterpolatedAttributeList<Ps>...>::template ExpandInto<gl::Attributes>; using AttributeBindings = typename Attributes::Bindings; template <class EvaluatedProperties> AttributeBindings attributeBindings(const EvaluatedProperties& currentProperties) const { - return AttributeBindings { - binders.template get<Ps>()->attributeBinding(currentProperties.template get<Ps>())... - }; + return AttributeBindings { std::tuple_cat( + binders.template get<Ps>()->attributeBinding(currentProperties.template get<Ps>())... + ) }; } - using Uniforms = gl::Uniforms<InterpolationUniform<typename Ps::Attribute>..., typename Ps::Uniform...>; + using Uniforms = typename TypeListConcat<InterpolationUniformList<Ps>..., typename Ps::Uniforms...>::template ExpandInto<gl::Uniforms>; using UniformValues = typename Uniforms::Values; template <class EvaluatedProperties> - UniformValues uniformValues(float currentZoom, const EvaluatedProperties& currentProperties) const { + UniformValues uniformValues(float currentZoom, EvaluatedProperties& currentProperties) const { (void)currentZoom; // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56958 - return UniformValues { - typename InterpolationUniform<typename Ps::Attribute>::Value { - binders.template get<Ps>()->interpolationFactor(currentZoom) - }..., - typename Ps::Uniform::Value { - binders.template get<Ps>()->uniformValue(currentProperties.template get<Ps>()) - }... - }; + return UniformValues ( + std::tuple_cat( + // interpolation uniform values + binders.template get<Ps>()->interpolationFactor(currentZoom)..., + // uniform values + binders.template get<Ps>()->uniformValue(currentProperties.template get<Ps>())...) + ); } template <class P> @@ -345,7 +506,6 @@ public: return binders.template get<P>()->statistics; } - using Bitset = std::bitset<sizeof...(Ps)>; template <class EvaluatedProperties> @@ -358,13 +518,25 @@ public: return result; } + template <class> + struct UniformDefines; + + template <class... Us> + struct UniformDefines<TypeList<Us...>> { + static void appendDefines(std::vector<std::string>& defines) { + util::ignore({ + (defines.push_back(std::string("#define HAS_UNIFORM_") + Us::name()), 0)... + }); + } + }; + template <class EvaluatedProperties> static std::vector<std::string> defines(const EvaluatedProperties& currentProperties) { std::vector<std::string> result; util::ignore({ - (result.push_back(currentProperties.template get<Ps>().isConstant() - ? std::string("#define HAS_UNIFORM_") + Ps::Uniform::name() - : std::string()), 0)... + (currentProperties.template get<Ps>().isConstant() + ? UniformDefines<typename Ps::Uniforms>::appendDefines(result) + : (void) 0, 0)... }); return result; } |