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 | |
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')
45 files changed, 853 insertions, 283 deletions
diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp index f48593ae49..7ccab8672d 100644 --- a/src/mbgl/renderer/bucket.hpp +++ b/src/mbgl/renderer/bucket.hpp @@ -3,7 +3,8 @@ #include <mbgl/util/noncopyable.hpp> #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/style/layer_type.hpp> - +#include <mbgl/style/image_impl.hpp> +#include <mbgl/renderer/image_atlas.hpp> #include <atomic> namespace mbgl { @@ -13,6 +14,8 @@ class Context; } // namespace gl class RenderLayer; +class PatternDependency; +using PatternLayerMap = std::unordered_map<std::string, PatternDependency>; class Bucket : private util::noncopyable { public: @@ -41,7 +44,12 @@ public: // Obtaining these is a costly operation, so we do it only once, and // pass-by-const-ref the geometries as a second parameter. virtual void addFeature(const GeometryTileFeature&, - const GeometryCollection&) {}; + const GeometryCollection&, + const ImagePositions&, + const PatternLayerMap&) {}; + + virtual void populateFeatureBuffers(const ImagePositions&) {}; + virtual void addPatternDependencies(const std::vector<const RenderLayer*>&, ImageDependencies&) {}; // As long as this bucket has a Prepare render pass, this function is getting called. Typically, // this only happens once when the bucket is being rendered for the first time. diff --git a/src/mbgl/renderer/buckets/circle_bucket.cpp b/src/mbgl/renderer/buckets/circle_bucket.cpp index d07c1f8dbe..820cf9f525 100644 --- a/src/mbgl/renderer/buckets/circle_bucket.cpp +++ b/src/mbgl/renderer/buckets/circle_bucket.cpp @@ -39,7 +39,9 @@ bool CircleBucket::hasData() const { } void CircleBucket::addFeature(const GeometryTileFeature& feature, - const GeometryCollection& geometry) { + const GeometryCollection& geometry, + const ImagePositions&, + const PatternLayerMap&) { constexpr const uint16_t vertexLength = 4; for (auto& circle : geometry) { @@ -87,7 +89,7 @@ void CircleBucket::addFeature(const GeometryTileFeature& feature, } for (auto& pair : paintPropertyBinders) { - pair.second.populateVertexVectors(feature, vertices.vertexSize()); + pair.second.populateVertexVectors(feature, vertices.vertexSize(), {}, {}); } } diff --git a/src/mbgl/renderer/buckets/circle_bucket.hpp b/src/mbgl/renderer/buckets/circle_bucket.hpp index 3c5f96fb15..db61a0c112 100644 --- a/src/mbgl/renderer/buckets/circle_bucket.hpp +++ b/src/mbgl/renderer/buckets/circle_bucket.hpp @@ -18,7 +18,10 @@ public: CircleBucket(const BucketParameters&, const std::vector<const RenderLayer*>&); void addFeature(const GeometryTileFeature&, - const GeometryCollection&) override; + const GeometryCollection&, + const ImagePositions&, + const PatternLayerMap&) override; + bool hasData() const override; void upload(gl::Context&) override; diff --git a/src/mbgl/renderer/buckets/fill_bucket.cpp b/src/mbgl/renderer/buckets/fill_bucket.cpp index 14be98c3af..3b1b7ec00f 100644 --- a/src/mbgl/renderer/buckets/fill_bucket.cpp +++ b/src/mbgl/renderer/buckets/fill_bucket.cpp @@ -27,20 +27,26 @@ using namespace style; struct GeometryTooLongException : std::exception {}; -FillBucket::FillBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) +FillBucket::FillBucket(const FillBucket::PossiblyEvaluatedLayoutProperties, + std::map<std::string, FillBucket::PossiblyEvaluatedPaintProperties> layerPaintProperties, + const float zoom, + const uint32_t) : Bucket(LayerType::Fill) { - for (const auto& layer : layers) { + + for (const auto& pair : layerPaintProperties) { paintPropertyBinders.emplace( std::piecewise_construct, - std::forward_as_tuple(layer->getID()), + std::forward_as_tuple(pair.first), std::forward_as_tuple( - layer->as<RenderFillLayer>()->evaluated, - parameters.tileID.overscaledZ)); + pair.second, + zoom)); } } void FillBucket::addFeature(const GeometryTileFeature& feature, - const GeometryCollection& geometry) { + const GeometryCollection& geometry, + const ImagePositions& patternPositions, + const PatternLayerMap& patternDependencies) { for (auto& polygon : classifyRings(geometry)) { // Optimize polygons with many interior rings for earcut tesselation. limitHoles(polygon, 500); @@ -105,7 +111,12 @@ void FillBucket::addFeature(const GeometryTileFeature& feature, } for (auto& pair : paintPropertyBinders) { - pair.second.populateVertexVectors(feature, vertices.vertexSize()); + const auto it = patternDependencies.find(pair.first); + if (it != patternDependencies.end()){ + pair.second.populateVertexVectors(feature, vertices.vertexSize(), patternPositions, it->second); + } else { + pair.second.populateVertexVectors(feature, vertices.vertexSize(), patternPositions, {}); + } } } diff --git a/src/mbgl/renderer/buckets/fill_bucket.hpp b/src/mbgl/renderer/buckets/fill_bucket.hpp index 20b65da39c..47e273d4d2 100644 --- a/src/mbgl/renderer/buckets/fill_bucket.hpp +++ b/src/mbgl/renderer/buckets/fill_bucket.hpp @@ -13,13 +13,26 @@ namespace mbgl { class BucketParameters; +class RenderFillLayer; class FillBucket : public Bucket { public: - FillBucket(const BucketParameters&, const std::vector<const RenderLayer*>&); + + // These aliases are used by the PatternLayout template + using RenderLayerType = RenderFillLayer; + using PossiblyEvaluatedPaintProperties = style::FillPaintProperties::PossiblyEvaluated; + using PossiblyEvaluatedLayoutProperties = style::Properties<>::PossiblyEvaluated; + + FillBucket(const PossiblyEvaluatedLayoutProperties layout, + std::map<std::string, PossiblyEvaluatedPaintProperties> layerPaintProperties, + const float zoom, + const uint32_t overscaling); void addFeature(const GeometryTileFeature&, - const GeometryCollection&) override; + const GeometryCollection&, + const mbgl::ImagePositions&, + const PatternLayerMap&) override; + bool hasData() const override; void upload(gl::Context&) override; diff --git a/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp index c6dba38db1..fe742828b8 100644 --- a/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp +++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp @@ -34,19 +34,26 @@ using namespace style; struct GeometryTooLongException : std::exception {}; -FillExtrusionBucket::FillExtrusionBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) +FillExtrusionBucket::FillExtrusionBucket(const FillExtrusionBucket::PossiblyEvaluatedLayoutProperties, + std::map<std::string, FillExtrusionBucket::PossiblyEvaluatedPaintProperties> layerPaintProperties, + const float zoom, + const uint32_t) : Bucket(LayerType::FillExtrusion) { - for (const auto& layer : layers) { - paintPropertyBinders.emplace(std::piecewise_construct, - std::forward_as_tuple(layer->getID()), - std::forward_as_tuple( - layer->as<RenderFillExtrusionLayer>()->evaluated, - parameters.tileID.overscaledZ)); + + for (const auto& pair : layerPaintProperties) { + paintPropertyBinders.emplace( + std::piecewise_construct, + std::forward_as_tuple(pair.first), + std::forward_as_tuple( + pair.second, + zoom)); } } void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature, - const GeometryCollection& geometry) { + const GeometryCollection& geometry, + const ImagePositions& patternPositions, + const PatternLayerMap& patternDependencies) { for (auto& polygon : classifyRings(geometry)) { // Optimize polygons with many interior rings for earcut tesselation. limitHoles(polygon, 500); @@ -143,7 +150,12 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature, } for (auto& pair : paintPropertyBinders) { - pair.second.populateVertexVectors(feature, vertices.vertexSize()); + const auto it = patternDependencies.find(pair.first); + if (it != patternDependencies.end()){ + pair.second.populateVertexVectors(feature, vertices.vertexSize(), patternPositions, it->second); + } else { + pair.second.populateVertexVectors(feature, vertices.vertexSize(), patternPositions, {}); + } } } diff --git a/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp index ed98e01292..362a9f4c99 100644 --- a/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp +++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp @@ -11,13 +11,26 @@ namespace mbgl { class BucketParameters; +class RenderFillExtrusionLayer; class FillExtrusionBucket : public Bucket { public: - FillExtrusionBucket(const BucketParameters&, const std::vector<const RenderLayer*>&); + + // These aliases are used by the PatternLayout template + using RenderLayerType = RenderFillExtrusionLayer; + using PossiblyEvaluatedPaintProperties = style::FillExtrusionPaintProperties::PossiblyEvaluated; + using PossiblyEvaluatedLayoutProperties = style::Properties<>::PossiblyEvaluated; + + FillExtrusionBucket(const PossiblyEvaluatedLayoutProperties, + std::map<std::string, PossiblyEvaluatedPaintProperties>, + const float, + const uint32_t); void addFeature(const GeometryTileFeature&, - const GeometryCollection&) override; + const GeometryCollection&, + const mbgl::ImagePositions&, + const PatternLayerMap&) override; + bool hasData() const override; void upload(gl::Context&) override; diff --git a/src/mbgl/renderer/buckets/heatmap_bucket.cpp b/src/mbgl/renderer/buckets/heatmap_bucket.cpp index eff0c60280..46d5f31599 100644 --- a/src/mbgl/renderer/buckets/heatmap_bucket.cpp +++ b/src/mbgl/renderer/buckets/heatmap_bucket.cpp @@ -39,7 +39,9 @@ bool HeatmapBucket::hasData() const { } void HeatmapBucket::addFeature(const GeometryTileFeature& feature, - const GeometryCollection& geometry) { + const GeometryCollection& geometry, + const ImagePositions&, + const PatternLayerMap&) { constexpr const uint16_t vertexLength = 4; for (auto& points : geometry) { @@ -87,7 +89,7 @@ void HeatmapBucket::addFeature(const GeometryTileFeature& feature, } for (auto& pair : paintPropertyBinders) { - pair.second.populateVertexVectors(feature, vertices.vertexSize()); + pair.second.populateVertexVectors(feature, vertices.vertexSize(), {}, {}); } } diff --git a/src/mbgl/renderer/buckets/heatmap_bucket.hpp b/src/mbgl/renderer/buckets/heatmap_bucket.hpp index 86b6f10296..b2d866d2a2 100644 --- a/src/mbgl/renderer/buckets/heatmap_bucket.hpp +++ b/src/mbgl/renderer/buckets/heatmap_bucket.hpp @@ -18,7 +18,9 @@ public: HeatmapBucket(const BucketParameters&, const std::vector<const RenderLayer*>&); void addFeature(const GeometryTileFeature&, - const GeometryCollection&) override; + const GeometryCollection&, + const ImagePositions&, + const PatternLayerMap&) override; bool hasData() const override; void upload(gl::Context&) override; diff --git a/src/mbgl/renderer/buckets/line_bucket.cpp b/src/mbgl/renderer/buckets/line_bucket.cpp index 80149edafe..2efb60c9ac 100644 --- a/src/mbgl/renderer/buckets/line_bucket.cpp +++ b/src/mbgl/renderer/buckets/line_bucket.cpp @@ -1,5 +1,4 @@ #include <mbgl/renderer/buckets/line_bucket.hpp> -#include <mbgl/renderer/layers/render_line_layer.hpp> #include <mbgl/renderer/bucket_parameters.hpp> #include <mbgl/style/layers/line_layer_impl.hpp> #include <mbgl/util/math.hpp> @@ -11,34 +10,45 @@ namespace mbgl { using namespace style; -LineBucket::LineBucket(const BucketParameters& parameters, - const std::vector<const RenderLayer*>& layers, - const style::LineLayoutProperties::Unevaluated& layout_) +LineBucket::LineBucket(const style::LineLayoutProperties::PossiblyEvaluated layout_, + std::map<std::string, RenderLinePaintProperties::PossiblyEvaluated> layerPaintProperties, + const float zoom_, + const uint32_t overscaling_) : Bucket(LayerType::Line), - layout(layout_.evaluate(PropertyEvaluationParameters(parameters.tileID.overscaledZ))), - overscaling(parameters.tileID.overscaleFactor()), - zoom(parameters.tileID.overscaledZ) { - for (const auto& layer : layers) { + layout(layout_), + zoom(zoom_), + overscaling(overscaling_) { + + for (const auto& pair : layerPaintProperties) { paintPropertyBinders.emplace( std::piecewise_construct, - std::forward_as_tuple(layer->getID()), + std::forward_as_tuple(pair.first), std::forward_as_tuple( - layer->as<RenderLineLayer>()->evaluated, - parameters.tileID.overscaledZ)); + pair.second, + zoom)); } } + void LineBucket::addFeature(const GeometryTileFeature& feature, - const GeometryCollection& geometryCollection) { + const GeometryCollection& geometryCollection, + const ImagePositions& patternPositions, + const PatternLayerMap& patternDependencies) { for (auto& line : geometryCollection) { addGeometry(line, feature); } for (auto& pair : paintPropertyBinders) { - pair.second.populateVertexVectors(feature, vertices.vertexSize()); + const auto it = patternDependencies.find(pair.first); + if (it != patternDependencies.end()){ + pair.second.populateVertexVectors(feature, vertices.vertexSize(), patternPositions, it->second); + } else { + pair.second.populateVertexVectors(feature, vertices.vertexSize(), patternPositions, {}); + } } } + /* * Sharp corners cause dashed lines to tilt because the distance along the line * is the same at both the inner and outer corners. To improve the appearance of @@ -130,7 +140,9 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates, const Geome const float miterLimit = joinType == LineJoinType::Bevel ? 1.05f : float(layout.get<LineMiterLimit>()); - const double sharpCornerOffset = SHARP_CORNER_OFFSET * (float(util::EXTENT) / (util::tileSize * overscaling)); + const double sharpCornerOffset = overscaling == 0 ? + SHARP_CORNER_OFFSET * (float(util::EXTENT) / util::tileSize) : + SHARP_CORNER_OFFSET * (float(util::EXTENT) / (util::tileSize * overscaling)); const GeometryCoordinate firstCoordinate = coordinates[first]; const LineCapType beginCap = layout.get<LineCap>(); diff --git a/src/mbgl/renderer/buckets/line_bucket.hpp b/src/mbgl/renderer/buckets/line_bucket.hpp index 23d30ca416..6bd37076de 100644 --- a/src/mbgl/renderer/buckets/line_bucket.hpp +++ b/src/mbgl/renderer/buckets/line_bucket.hpp @@ -1,5 +1,4 @@ #pragma once - #include <mbgl/renderer/bucket.hpp> #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/gl/vertex_buffer.hpp> @@ -7,6 +6,7 @@ #include <mbgl/programs/segment.hpp> #include <mbgl/programs/line_program.hpp> #include <mbgl/style/layers/line_layer_properties.hpp> +#include <mbgl/style/image_impl.hpp> #include <vector> @@ -17,19 +17,29 @@ class RenderLineLayer; class LineBucket : public Bucket { public: - LineBucket(const BucketParameters&, - const std::vector<const RenderLayer*>&, - const style::LineLayoutProperties::Unevaluated&); + + // These aliases are used by the PatternLayout template + using RenderLayerType = RenderLineLayer; + using PossiblyEvaluatedPaintProperties = RenderLinePaintProperties::PossiblyEvaluated; + using PossiblyEvaluatedLayoutProperties = style::LineLayoutProperties::PossiblyEvaluated; + + LineBucket(const PossiblyEvaluatedLayoutProperties layout, + std::map<std::string, PossiblyEvaluatedPaintProperties> layerPaintProperties, + const float zoom, + const uint32_t overscaling); void addFeature(const GeometryTileFeature&, - const GeometryCollection&) override; + const GeometryCollection&, + const mbgl::ImagePositions& patternPositions, + const PatternLayerMap&) override; + bool hasData() const override; void upload(gl::Context&) override; float getQueryRadius(const RenderLayer&) const override; - style::LineLayoutProperties::PossiblyEvaluated layout; + PossiblyEvaluatedLayoutProperties layout; gl::VertexVector<LineLayoutVertex> vertices; gl::IndexVector<gl::Triangles> triangles; @@ -63,8 +73,8 @@ private: std::ptrdiff_t e2; std::ptrdiff_t e3; - const uint32_t overscaling; const float zoom; + const uint32_t overscaling; float getLineWidth(const RenderLineLayer& layer) const; }; diff --git a/src/mbgl/renderer/cross_faded_property_evaluator.cpp b/src/mbgl/renderer/cross_faded_property_evaluator.cpp index 9a7af8636c..7be9c2bcf5 100644 --- a/src/mbgl/renderer/cross_faded_property_evaluator.cpp +++ b/src/mbgl/renderer/cross_faded_property_evaluator.cpp @@ -25,16 +25,9 @@ Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const style::PropertyExpress template <typename T> Faded<T> CrossFadedPropertyEvaluator<T>::calculate(const T& min, const T& mid, const T& max) const { const float z = parameters.z; - const float fraction = z - std::floor(z); - const std::chrono::duration<float> d = parameters.defaultFadeDuration; - const float t = - d != std::chrono::duration<float>::zero() - ? std::min((parameters.now - parameters.zoomHistory.lastIntegerZoomTime) / d, 1.0f) - : 1.0f; - return z > parameters.zoomHistory.lastIntegerZoom - ? Faded<T> { min, mid, 2.0f, 1.0f, fraction + (1.0f - fraction) * t } - : Faded<T> { max, mid, 0.5f, 1.0f, 1 - (1 - t) * fraction }; + ? Faded<T> { min, mid } + : Faded<T> { max, mid }; } template class CrossFadedPropertyEvaluator<std::string>; diff --git a/src/mbgl/renderer/cross_faded_property_evaluator.hpp b/src/mbgl/renderer/cross_faded_property_evaluator.hpp index 1d17c5eb2f..e925b96fa3 100644 --- a/src/mbgl/renderer/cross_faded_property_evaluator.hpp +++ b/src/mbgl/renderer/cross_faded_property_evaluator.hpp @@ -11,9 +11,6 @@ class Faded { public: T from; T to; - float fromScale; - float toScale; - float t; }; template <typename T> diff --git a/src/mbgl/renderer/data_driven_property_evaluator.hpp b/src/mbgl/renderer/data_driven_property_evaluator.hpp index f9452cc572..d65ac36713 100644 --- a/src/mbgl/renderer/data_driven_property_evaluator.hpp +++ b/src/mbgl/renderer/data_driven_property_evaluator.hpp @@ -3,6 +3,7 @@ #include <mbgl/style/property_value.hpp> #include <mbgl/renderer/property_evaluation_parameters.hpp> #include <mbgl/renderer/possibly_evaluated_property_value.hpp> +#include <mbgl/renderer/cross_faded_property_evaluator.hpp> namespace mbgl { @@ -40,4 +41,43 @@ private: T defaultValue; }; +template <typename T> +class DataDrivenPropertyEvaluator<Faded<T>> { +public: + using ResultType = PossiblyEvaluatedPropertyValue<Faded<T>>; + + DataDrivenPropertyEvaluator(const PropertyEvaluationParameters& parameters_, T defaultValue_) + : parameters(parameters_), + defaultValue(std::move(defaultValue_)) {} + + ResultType operator()(const T& constant) const { + return ResultType(calculate(constant, constant, constant)); + } + + ResultType operator()(const style::Undefined& ) const { + return ResultType(calculate(defaultValue, defaultValue, defaultValue)); + } + + ResultType operator()(const style::PropertyExpression<T>& expression) const { + if (!expression.isFeatureConstant()) { + return ResultType(expression); + } else { + const T evaluated = expression.evaluate(floor(parameters.z)); + return ResultType(calculate(evaluated, evaluated, evaluated)); + } + } + + +private: + Faded<T> calculate(const T& min, const T& mid, const T& max) const { + const float z = parameters.z; + return z > parameters.zoomHistory.lastIntegerZoom + ? Faded<T> { min, mid } + : Faded<T> { max, mid }; + }; + + const PropertyEvaluationParameters& parameters; + T defaultValue; +}; + } // namespace mbgl diff --git a/src/mbgl/renderer/image_atlas.cpp b/src/mbgl/renderer/image_atlas.cpp index 8eee7c2095..b39c788ced 100644 --- a/src/mbgl/renderer/image_atlas.cpp +++ b/src/mbgl/renderer/image_atlas.cpp @@ -16,36 +16,56 @@ ImagePosition::ImagePosition(const mapbox::Bin& bin, const style::Image::Impl& i ) { } -ImageAtlas makeImageAtlas(const ImageMap& images) { +const mapbox::Bin& _packImage(mapbox::ShelfPack& pack, const style::Image::Impl& image, ImageAtlas& resultImage, ImageType imageType) { + const mapbox::Bin& bin = *pack.packOne(-1, + image.image.size.width + 2 * padding, + image.image.size.height + 2 * padding); + + resultImage.image.resize({ + static_cast<uint32_t>(pack.width()), + static_cast<uint32_t>(pack.height()) + }); + + PremultipliedImage::copy(image.image, + resultImage.image, + { 0, 0 }, + { + bin.x + padding, + bin.y + padding + }, + image.image.size); + uint32_t x = bin.x + padding, + y = bin.y + padding, + w = image.image.size.width, + h = image.image.size.height; + + if (imageType == ImageType::Pattern) { + // Add 1 pixel wrapped padding on each side of the image. + PremultipliedImage::copy(image.image, resultImage.image, { 0, h - 1 }, { x, y - 1 }, { w, 1 }); // T + PremultipliedImage::copy(image.image, resultImage.image, { 0, 0 }, { x, y + h }, { w, 1 }); // B + PremultipliedImage::copy(image.image, resultImage.image, { w - 1, 0 }, { x - 1, y }, { 1, h }); // L + PremultipliedImage::copy(image.image, resultImage.image, { 0, 0 }, { x + w, y }, { 1, h }); // R + } + return bin; +} + +ImageAtlas makeImageAtlas(const ImageMap& icons, const ImageMap& patterns) { ImageAtlas result; mapbox::ShelfPack::ShelfPackOptions options; options.autoResize = true; mapbox::ShelfPack pack(0, 0, options); - for (const auto& entry : images) { + for (const auto& entry : icons) { const style::Image::Impl& image = *entry.second; + const mapbox::Bin& bin = _packImage(pack, image, result, ImageType::Icon); + result.iconPositions.emplace(image.id, ImagePosition { bin, image }); + } - const mapbox::Bin& bin = *pack.packOne(-1, - image.image.size.width + 2 * padding, - image.image.size.height + 2 * padding); - - result.image.resize({ - static_cast<uint32_t>(pack.width()), - static_cast<uint32_t>(pack.height()) - }); - - PremultipliedImage::copy(image.image, - result.image, - { 0, 0 }, - { - bin.x + padding, - bin.y + padding - }, - image.image.size); - - result.positions.emplace(image.id, - ImagePosition { bin, image }); + for (const auto& entry : patterns) { + const style::Image::Impl& image = *entry.second; + const mapbox::Bin& bin = _packImage(pack, image, result, ImageType::Pattern); + result.patternPositions.emplace(image.id, ImagePosition { bin, image }); } pack.shrink(); diff --git a/src/mbgl/renderer/image_atlas.hpp b/src/mbgl/renderer/image_atlas.hpp index b3cc166eff..3af31a75f8 100644 --- a/src/mbgl/renderer/image_atlas.hpp +++ b/src/mbgl/renderer/image_atlas.hpp @@ -30,6 +30,12 @@ public: }}; } + std::array<uint16_t, 4> tlbr() const { + const auto _tl = tl(); + const auto _br = br(); + return {{ _tl[0], _tl[1], _br[0], _br[1] }}; + } + std::array<float, 2> displaySize() const { return {{ textureRect.w / pixelRatio, @@ -43,9 +49,10 @@ using ImagePositions = std::map<std::string, ImagePosition>; class ImageAtlas { public: PremultipliedImage image; - ImagePositions positions; + ImagePositions iconPositions; + ImagePositions patternPositions; }; -ImageAtlas makeImageAtlas(const ImageMap&); +ImageAtlas makeImageAtlas(const ImageMap&, const ImageMap&); } // namespace mbgl diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp index 2ef6be0c4f..fc1f5bb167 100644 --- a/src/mbgl/renderer/image_manager.cpp +++ b/src/mbgl/renderer/image_manager.cpp @@ -67,7 +67,7 @@ void ImageManager::getImages(ImageRequestor& requestor, ImageRequestPair&& pair) bool hasAllDependencies = true; if (!isLoaded()) { for (const auto& dependency : pair.first) { - if (images.find(dependency) == images.end()) { + if (images.find(dependency.first) == images.end()) { hasAllDependencies = false; } } @@ -84,16 +84,17 @@ void ImageManager::removeRequestor(ImageRequestor& requestor) { } void ImageManager::notify(ImageRequestor& requestor, const ImageRequestPair& pair) const { - ImageMap response; + ImageMap iconMap; + ImageMap patternMap; for (const auto& dependency : pair.first) { - auto it = images.find(dependency); + auto it = images.find(dependency.first); if (it != images.end()) { - response.emplace(*it); + dependency.second == ImageType::Pattern ? patternMap.emplace(*it) : iconMap.emplace(*it); } } - requestor.onImagesAvailable(response, pair.second); + requestor.onImagesAvailable(iconMap, patternMap, pair.second); } void ImageManager::dumpDebugLogs() const { diff --git a/src/mbgl/renderer/image_manager.hpp b/src/mbgl/renderer/image_manager.hpp index f72ba9fb53..103491c58b 100644 --- a/src/mbgl/renderer/image_manager.hpp +++ b/src/mbgl/renderer/image_manager.hpp @@ -21,7 +21,7 @@ class Context; class ImageRequestor { public: virtual ~ImageRequestor() = default; - virtual void onImagesAvailable(ImageMap, uint64_t imageCorrelationID) = 0; + virtual void onImagesAvailable(ImageMap icons, ImageMap patterns, uint64_t imageCorrelationID) = 0; }; /* diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp index 2dc5fe7339..ad85fe0cce 100644 --- a/src/mbgl/renderer/layers/render_background_layer.cpp +++ b/src/mbgl/renderer/layers/render_background_layer.cpp @@ -34,6 +34,7 @@ void RenderBackgroundLayer::transition(const TransitionParameters ¶meters) { void RenderBackgroundLayer::evaluate(const PropertyEvaluationParameters ¶meters) { evaluated = unevaluated.evaluate(parameters); + crossfade = parameters.getCrossfadeParameters(); passes = evaluated.get<style::BackgroundOpacity>() > 0 ? RenderPass::Translucent : RenderPass::None; @@ -43,6 +44,10 @@ bool RenderBackgroundLayer::hasTransition() const { return unevaluated.hasTransition(); } +bool RenderBackgroundLayer::hasCrossfade() const { + return crossfade.t != 1; +} + void RenderBackgroundLayer::render(PaintParameters& parameters, RenderSource*) { // Note that for bottommost layers without a pattern, the background color is drawn with // glClear rather than this method. @@ -97,7 +102,7 @@ void RenderBackgroundLayer::render(PaintParameters& parameters, RenderSource*) { parameters.imageManager.getPixelSize(), *imagePosA, *imagePosB, - evaluated.get<BackgroundPattern>(), + crossfade, tileID, parameters.state ) @@ -108,9 +113,9 @@ void RenderBackgroundLayer::render(PaintParameters& parameters, RenderSource*) { draw( parameters.programs.background, BackgroundProgram::UniformValues { - uniforms::u_matrix::Value{ parameters.matrixForTile(tileID) }, - uniforms::u_color::Value{ evaluated.get<BackgroundColor>() }, - uniforms::u_opacity::Value{ evaluated.get<BackgroundOpacity>() }, + uniforms::u_matrix::Value( parameters.matrixForTile(tileID) ), + uniforms::u_color::Value( evaluated.get<BackgroundColor>() ), + uniforms::u_opacity::Value( evaluated.get<BackgroundOpacity>() ), } ); } diff --git a/src/mbgl/renderer/layers/render_background_layer.hpp b/src/mbgl/renderer/layers/render_background_layer.hpp index a619670ee4..854c077a62 100644 --- a/src/mbgl/renderer/layers/render_background_layer.hpp +++ b/src/mbgl/renderer/layers/render_background_layer.hpp @@ -14,6 +14,7 @@ public: void transition(const TransitionParameters&) override; void evaluate(const PropertyEvaluationParameters&) override; bool hasTransition() const override; + bool hasCrossfade() const override; void render(PaintParameters&, RenderSource*) override; std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override; @@ -23,6 +24,8 @@ public: style::BackgroundPaintProperties::PossiblyEvaluated evaluated; const style::BackgroundLayer::Impl& impl() const; +private: + CrossfadeParameters crossfade; }; template <> diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index ce63ada770..af96e2e991 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -47,6 +47,10 @@ bool RenderCircleLayer::hasTransition() const { return unevaluated.hasTransition(); } +bool RenderCircleLayer::hasCrossfade() const { + return false; +} + void RenderCircleLayer::render(PaintParameters& parameters, RenderSource*) { if (parameters.pass == RenderPass::Opaque) { return; @@ -68,19 +72,19 @@ void RenderCircleLayer::render(PaintParameters& parameters, RenderSource*) { const auto allUniformValues = programInstance.computeAllUniformValues( CircleProgram::UniformValues { - uniforms::u_matrix::Value{ + uniforms::u_matrix::Value( tile.translatedMatrix(evaluated.get<CircleTranslate>(), evaluated.get<CircleTranslateAnchor>(), parameters.state) - }, - uniforms::u_scale_with_map::Value{ scaleWithMap }, - uniforms::u_extrude_scale::Value{ pitchWithMap + ), + uniforms::u_scale_with_map::Value( scaleWithMap ), + uniforms::u_extrude_scale::Value( pitchWithMap ? std::array<float, 2> {{ tile.id.pixelsToTileUnits(1, parameters.state.getZoom()), tile.id.pixelsToTileUnits(1, parameters.state.getZoom()) }} - : parameters.pixelsToGLUnits }, - uniforms::u_camera_to_center_distance::Value{ parameters.state.getCameraToCenterDistance() }, - uniforms::u_pitch_with_map::Value{ pitchWithMap } + : parameters.pixelsToGLUnits ), + uniforms::u_camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() ), + uniforms::u_pitch_with_map::Value( pitchWithMap ) }, paintPropertyBinders, evaluated, diff --git a/src/mbgl/renderer/layers/render_circle_layer.hpp b/src/mbgl/renderer/layers/render_circle_layer.hpp index c9eeae4652..53353fcdcb 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.hpp +++ b/src/mbgl/renderer/layers/render_circle_layer.hpp @@ -14,6 +14,7 @@ public: void transition(const TransitionParameters&) override; void evaluate(const PropertyEvaluationParameters&) override; bool hasTransition() const override; + bool hasCrossfade() const override; void render(PaintParameters&, RenderSource*) override; bool queryIntersectsFeature( diff --git a/src/mbgl/renderer/layers/render_custom_layer.cpp b/src/mbgl/renderer/layers/render_custom_layer.cpp index be9f64d9eb..16c18447c5 100644 --- a/src/mbgl/renderer/layers/render_custom_layer.cpp +++ b/src/mbgl/renderer/layers/render_custom_layer.cpp @@ -38,6 +38,9 @@ void RenderCustomLayer::evaluate(const PropertyEvaluationParameters&) { bool RenderCustomLayer::hasTransition() const { return false; } +bool RenderCustomLayer::hasCrossfade() const { + return false; +} std::unique_ptr<Bucket> RenderCustomLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const { assert(false); diff --git a/src/mbgl/renderer/layers/render_custom_layer.hpp b/src/mbgl/renderer/layers/render_custom_layer.hpp index 971d8d8f42..47d5bb3f40 100644 --- a/src/mbgl/renderer/layers/render_custom_layer.hpp +++ b/src/mbgl/renderer/layers/render_custom_layer.hpp @@ -13,6 +13,7 @@ public: void transition(const TransitionParameters&) final {} void evaluate(const PropertyEvaluationParameters&) override; bool hasTransition() const override; + bool hasCrossfade() const override; std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const final; void render(PaintParameters&, RenderSource*) final; diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index 2f720284fc..08e9d609cd 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -12,6 +12,7 @@ #include <mbgl/geometry/feature_index.hpp> #include <mbgl/util/math.hpp> #include <mbgl/util/intersection_tests.hpp> +#include <mbgl/tile/geometry_tile.hpp> namespace mbgl { @@ -26,8 +27,18 @@ const style::FillExtrusionLayer::Impl& RenderFillExtrusionLayer::impl() const { return static_cast<const style::FillExtrusionLayer::Impl&>(*baseImpl); } -std::unique_ptr<Bucket> RenderFillExtrusionLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const { - return std::make_unique<FillExtrusionBucket>(parameters, layers); +std::unique_ptr<Bucket> RenderFillExtrusionLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const { + assert(false); // Should be calling createLayout() instead. + return nullptr; +} + + +std::unique_ptr<PatternLayout<FillExtrusionBucket>> +RenderFillExtrusionLayer::createLayout(const BucketParameters& parameters, + const std::vector<const RenderLayer*>& group, + std::unique_ptr<GeometryTileLayer> layer, + ImageDependencies& imageDependencies) const { + return std::make_unique<PatternLayout<FillExtrusionBucket>>(parameters, group, std::move(layer), imageDependencies); } void RenderFillExtrusionLayer::transition(const TransitionParameters& parameters) { @@ -36,6 +47,7 @@ void RenderFillExtrusionLayer::transition(const TransitionParameters& parameters void RenderFillExtrusionLayer::evaluate(const PropertyEvaluationParameters& parameters) { evaluated = unevaluated.evaluate(parameters); + crossfade = parameters.getCrossfadeParameters(); passes = (evaluated.get<style::FillExtrusionOpacity>() > 0) ? (RenderPass::Translucent | RenderPass::Pass3D) @@ -46,6 +58,10 @@ bool RenderFillExtrusionLayer::hasTransition() const { return unevaluated.hasTransition(); } +bool RenderFillExtrusionLayer::hasCrossfade() const { + return crossfade.t != 1; +} + void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource*) { if (parameters.pass == RenderPass::Opaque) { return; @@ -68,8 +84,10 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* parameters.context.setStencilMode(gl::StencilMode::disabled()); parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, depthClearValue, {}); - auto draw = [&](auto& programInstance, const auto& tileBucket, auto&& uniformValues) { + auto draw = [&](auto& programInstance, const auto& tileBucket, auto&& uniformValues, + const optional<ImagePosition>& patternPositionA, const optional<ImagePosition>& patternPositionB) { const auto& paintPropertyBinders = tileBucket.paintPropertyBinders.at(getID()); + paintPropertyBinders.setPatternParameters(patternPositionA, patternPositionB, crossfade); const auto allUniformValues = programInstance.computeAllUniformValues( std::move(uniformValues), @@ -98,7 +116,7 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* getID()); }; - if (evaluated.get<FillExtrusionPattern>().from.empty()) { + if (unevaluated.get<FillExtrusionPattern>().isUndefined()) { for (const RenderTile& tile : renderTiles) { auto bucket_ = tile.tile.getBucket<FillExtrusionBucket>(*baseImpl); if (!bucket_) { @@ -115,26 +133,22 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* parameters.state), parameters.state, parameters.evaluatedLight - ) + ), + {}, {} ); } } else { - optional<ImagePosition> imagePosA = - parameters.imageManager.getPattern(evaluated.get<FillExtrusionPattern>().from); - optional<ImagePosition> imagePosB = - parameters.imageManager.getPattern(evaluated.get<FillExtrusionPattern>().to); - - if (!imagePosA || !imagePosB) { - return; - } - - parameters.imageManager.bind(parameters.context, 0); - for (const RenderTile& tile : renderTiles) { auto bucket_ = tile.tile.getBucket<FillExtrusionBucket>(*baseImpl); if (!bucket_) { continue; } + const auto fillPatternValue = evaluated.get<FillExtrusionPattern>().constantOr(mbgl::Faded<std::basic_string<char> >{"", ""}); + assert(dynamic_cast<GeometryTile*>(&tile.tile)); + GeometryTile& geometryTile = static_cast<GeometryTile&>(tile.tile); + optional<ImagePosition> patternPosA = geometryTile.getPattern(fillPatternValue.from); + optional<ImagePosition> patternPosB = geometryTile.getPattern(fillPatternValue.to); + parameters.context.bindTexture(*geometryTile.iconAtlasTexture, 0, gl::TextureFilter::Linear); FillExtrusionBucket& bucket = *bucket_; draw( @@ -144,11 +158,16 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(), evaluated.get<FillExtrusionTranslateAnchor>(), parameters.state), - parameters.imageManager.getPixelSize(), *imagePosA, *imagePosB, - evaluated.get<FillExtrusionPattern>(), tile.id, parameters.state, + geometryTile.iconAtlasTexture->size, + crossfade, + tile.id, + parameters.state, -std::pow(2, tile.id.canonical.z) / util::tileSize / 8.0f, + parameters.pixelRatio, parameters.evaluatedLight - ) + ), + patternPosA, + patternPosB ); } } @@ -168,9 +187,9 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* const auto allUniformValues = programInstance.computeAllUniformValues( ExtrusionTextureProgram::UniformValues{ - uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size }, - uniforms::u_image::Value{ 0 }, - uniforms::u_opacity::Value{ evaluated.get<FillExtrusionOpacity>() } + uniforms::u_matrix::Value( viewportMat ), uniforms::u_world::Value( size ), + uniforms::u_image::Value( 0 ), + uniforms::u_opacity::Value( evaluated.get<FillExtrusionOpacity>() ) }, paintAttributeData, properties, @@ -197,6 +216,17 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* getID()); } } +style::FillExtrusionPaintProperties::PossiblyEvaluated RenderFillExtrusionLayer::paintProperties() const { + return FillExtrusionPaintProperties::PossiblyEvaluated { + evaluated.get<style::FillExtrusionOpacity>(), + evaluated.get<style::FillExtrusionColor>(), + evaluated.get<style::FillExtrusionTranslate>(), + evaluated.get<style::FillExtrusionTranslateAnchor>(), + evaluated.get<style::FillExtrusionPattern>(), + evaluated.get<style::FillExtrusionHeight>(), + evaluated.get<style::FillExtrusionBase>() + }; +} bool RenderFillExtrusionLayer::queryIntersectsFeature( const GeometryCoordinates& queryGeometry, diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp index f7ba13c267..1a721d035b 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp @@ -8,15 +8,25 @@ namespace mbgl { +template <class B> +class PatternLayout; + +class FillExtrusionBucket; + class RenderFillExtrusionLayer: public RenderLayer { public: + using StyleLayerImpl = style::FillExtrusionLayer::Impl; + using PatternProperty = style::FillExtrusionPattern; + RenderFillExtrusionLayer(Immutable<style::FillExtrusionLayer::Impl>); ~RenderFillExtrusionLayer() final = default; void transition(const TransitionParameters&) override; void evaluate(const PropertyEvaluationParameters&) override; bool hasTransition() const override; + bool hasCrossfade() const override; void render(PaintParameters&, RenderSource*) override; + style::FillExtrusionPaintProperties::PossiblyEvaluated paintProperties() const; bool queryIntersectsFeature( const GeometryCoordinates&, @@ -28,6 +38,9 @@ public: std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override; + std::unique_ptr<PatternLayout<FillExtrusionBucket>> + createLayout(const BucketParameters&, const std::vector<const RenderLayer*>&, std::unique_ptr<GeometryTileLayer>, ImageDependencies&) const; + // Paint properties style::FillExtrusionPaintProperties::Unevaluated unevaluated; style::FillExtrusionPaintProperties::PossiblyEvaluated evaluated; @@ -35,6 +48,8 @@ public: const style::FillExtrusionLayer::Impl& impl() const; optional<OffscreenTexture> renderTexture; +private: + CrossfadeParameters crossfade; }; template <> diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index f03eb66c88..5d7ed02da8 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -10,6 +10,7 @@ #include <mbgl/geometry/feature_index.hpp> #include <mbgl/util/math.hpp> #include <mbgl/util/intersection_tests.hpp> +#include <mbgl/tile/geometry_tile.hpp> namespace mbgl { @@ -24,8 +25,17 @@ const style::FillLayer::Impl& RenderFillLayer::impl() const { return static_cast<const style::FillLayer::Impl&>(*baseImpl); } -std::unique_ptr<Bucket> RenderFillLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const { - return std::make_unique<FillBucket>(parameters, layers); +std::unique_ptr<Bucket> RenderFillLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const { + assert(false); // Should be calling createLayout() instead. + return nullptr; +} + +std::unique_ptr<PatternLayout<FillBucket>> +RenderFillLayer::createLayout(const BucketParameters& parameters, + const std::vector<const RenderLayer*>& group, + std::unique_ptr<GeometryTileLayer> layer, + ImageDependencies& imageDependencies) const { + return std::make_unique<PatternLayout<FillBucket>>(parameters, group, std::move(layer), imageDependencies); } void RenderFillLayer::transition(const TransitionParameters& parameters) { @@ -34,6 +44,7 @@ void RenderFillLayer::transition(const TransitionParameters& parameters) { void RenderFillLayer::evaluate(const PropertyEvaluationParameters& parameters) { evaluated = unevaluated.evaluate(parameters); + crossfade = parameters.getCrossfadeParameters(); if (unevaluated.get<style::FillOutlineColor>().isUndefined()) { evaluated.get<style::FillOutlineColor>() = evaluated.get<style::FillColor>(); @@ -58,8 +69,12 @@ bool RenderFillLayer::hasTransition() const { return unevaluated.hasTransition(); } +bool RenderFillLayer::hasCrossfade() const { + return crossfade.t != 1; +} + void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { - if (evaluated.get<FillPattern>().from.empty()) { + if (unevaluated.get<FillPattern>().isUndefined()) { for (const RenderTile& tile : renderTiles) { auto bucket_ = tile.tile.getBucket<FillBucket>(*baseImpl); if (!bucket_) { @@ -78,12 +93,12 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { const auto allUniformValues = programInstance.computeAllUniformValues( FillProgram::UniformValues { - uniforms::u_matrix::Value{ + uniforms::u_matrix::Value( tile.translatedMatrix(evaluated.get<FillTranslate>(), evaluated.get<FillTranslateAnchor>(), parameters.state) - }, - uniforms::u_world::Value{ parameters.context.viewport.getCurrentValue().size }, + ), + uniforms::u_world::Value( parameters.context.viewport.getCurrentValue().size ), }, paintPropertyBinders, evaluated, @@ -138,17 +153,14 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { if (parameters.pass != RenderPass::Translucent) { return; } - - optional<ImagePosition> imagePosA = parameters.imageManager.getPattern(evaluated.get<FillPattern>().from); - optional<ImagePosition> imagePosB = parameters.imageManager.getPattern(evaluated.get<FillPattern>().to); - - if (!imagePosA || !imagePosB) { - return; - } - - parameters.imageManager.bind(parameters.context, 0); - + const auto fillPatternValue = evaluated.get<FillPattern>().constantOr(Faded<std::basic_string<char>>{"", ""}); for (const RenderTile& tile : renderTiles) { + assert(dynamic_cast<GeometryTile*>(&tile.tile)); + GeometryTile& geometryTile = static_cast<GeometryTile&>(tile.tile); + optional<ImagePosition> patternPosA = geometryTile.getPattern(fillPatternValue.from); + optional<ImagePosition> patternPosB = geometryTile.getPattern(fillPatternValue.to); + + parameters.context.bindTexture(*geometryTile.iconAtlasTexture, 0, gl::TextureFilter::Linear); auto bucket_ = tile.tile.getBucket<FillBucket>(*baseImpl); if (!bucket_) { continue; @@ -163,6 +175,7 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { auto& programInstance = program.get(evaluated); const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + paintPropertyBinders.setPatternParameters(patternPosA, patternPosB, crossfade); const auto allUniformValues = programInstance.computeAllUniformValues( FillPatternUniforms::values( @@ -170,12 +183,11 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { evaluated.get<FillTranslateAnchor>(), parameters.state), parameters.context.viewport.getCurrentValue().size, - parameters.imageManager.getPixelSize(), - *imagePosA, - *imagePosB, - evaluated.get<FillPattern>(), + geometryTile.iconAtlasTexture->size, + crossfade, tile.id, - parameters.state + parameters.state, + parameters.pixelRatio ), paintPropertyBinders, evaluated, @@ -220,6 +232,18 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { } } +style::FillPaintProperties::PossiblyEvaluated RenderFillLayer::paintProperties() const { + return FillPaintProperties::PossiblyEvaluated { + evaluated.get<style::FillAntialias>(), + evaluated.get<style::FillOpacity>(), + evaluated.get<style::FillColor>(), + evaluated.get<style::FillOutlineColor>(), + evaluated.get<style::FillTranslate>(), + evaluated.get<style::FillTranslateAnchor>(), + evaluated.get<style::FillPattern>() + }; +} + bool RenderFillLayer::queryIntersectsFeature( const GeometryCoordinates& queryGeometry, const GeometryTileFeature& feature, diff --git a/src/mbgl/renderer/layers/render_fill_layer.hpp b/src/mbgl/renderer/layers/render_fill_layer.hpp index bd195fb828..5a3c05387d 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.hpp +++ b/src/mbgl/renderer/layers/render_fill_layer.hpp @@ -3,18 +3,26 @@ #include <mbgl/renderer/render_layer.hpp> #include <mbgl/style/layers/fill_layer_impl.hpp> #include <mbgl/style/layers/fill_layer_properties.hpp> +#include <mbgl/layout/pattern_layout.hpp> namespace mbgl { +class FillBucket; + class RenderFillLayer: public RenderLayer { public: + using StyleLayerImpl = style::FillLayer::Impl; + using PatternProperty = style::FillPattern; + RenderFillLayer(Immutable<style::FillLayer::Impl>); ~RenderFillLayer() final = default; void transition(const TransitionParameters&) override; void evaluate(const PropertyEvaluationParameters&) override; bool hasTransition() const override; + bool hasCrossfade() const override; void render(PaintParameters&, RenderSource*) override; + style::FillPaintProperties::PossiblyEvaluated paintProperties() const; bool queryIntersectsFeature( const GeometryCoordinates&, @@ -26,11 +34,17 @@ public: std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override; + std::unique_ptr<PatternLayout<FillBucket>> + createLayout(const BucketParameters&, const std::vector<const RenderLayer*>&, std::unique_ptr<GeometryTileLayer>, ImageDependencies&) const; + // Paint properties style::FillPaintProperties::Unevaluated unevaluated; style::FillPaintProperties::PossiblyEvaluated evaluated; const style::FillLayer::Impl& impl() const; +private: + CrossfadeParameters crossfade; + }; template <> diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index c9ca477cbb..8e24cf8f32 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -45,6 +45,10 @@ bool RenderHeatmapLayer::hasTransition() const { return unevaluated.hasTransition(); } +bool RenderHeatmapLayer::hasCrossfade() const { + return false; +} + void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { if (parameters.pass == RenderPass::Opaque) { return; @@ -101,9 +105,9 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { const auto allUniformValues = programInstance.computeAllUniformValues( HeatmapProgram::UniformValues { - uniforms::u_intensity::Value{ evaluated.get<style::HeatmapIntensity>() }, - uniforms::u_matrix::Value{ tile.matrix }, - uniforms::heatmap::u_extrude_scale::Value{ extrudeScale } + uniforms::u_intensity::Value( evaluated.get<style::HeatmapIntensity>() ), + uniforms::u_matrix::Value( tile.matrix ), + uniforms::heatmap::u_extrude_scale::Value( extrudeScale ) }, paintPropertyBinders, evaluated, @@ -147,10 +151,10 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { const auto allUniformValues = programInstance.computeAllUniformValues( HeatmapTextureProgram::UniformValues{ - uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size }, - uniforms::u_image::Value{ 0 }, - uniforms::u_color_ramp::Value{ 1 }, - uniforms::u_opacity::Value{ evaluated.get<HeatmapOpacity>() } + uniforms::u_matrix::Value( viewportMat ), uniforms::u_world::Value( size ), + uniforms::u_image::Value( 0 ), + uniforms::u_color_ramp::Value( 1 ), + uniforms::u_opacity::Value( evaluated.get<HeatmapOpacity>() ) }, paintAttributeData, properties, diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.hpp b/src/mbgl/renderer/layers/render_heatmap_layer.hpp index 29fad7d8b8..6f8163ebf1 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.hpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.hpp @@ -16,6 +16,7 @@ public: void transition(const TransitionParameters&) override; void evaluate(const PropertyEvaluationParameters&) override; bool hasTransition() const override; + bool hasCrossfade() const override; void render(PaintParameters&, RenderSource*) override; bool queryIntersectsFeature( diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.cpp b/src/mbgl/renderer/layers/render_hillshade_layer.cpp index 8bcd3f1837..b96030f44d 100644 --- a/src/mbgl/renderer/layers/render_hillshade_layer.cpp +++ b/src/mbgl/renderer/layers/render_hillshade_layer.cpp @@ -56,6 +56,10 @@ bool RenderHillshadeLayer::hasTransition() const { return unevaluated.hasTransition(); } +bool RenderHillshadeLayer::hasCrossfade() const { + return false; +} + void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src) { if (parameters.pass != RenderPass::Translucent && parameters.pass != RenderPass::Pass3D) return; @@ -75,13 +79,13 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src const auto allUniformValues = programInstance.computeAllUniformValues( HillshadeProgram::UniformValues { - uniforms::u_matrix::Value{ matrix }, - uniforms::u_image::Value{ 0 }, - uniforms::u_highlight::Value{ evaluated.get<HillshadeHighlightColor>() }, - uniforms::u_shadow::Value{ evaluated.get<HillshadeShadowColor>() }, - uniforms::u_accent::Value{ evaluated.get<HillshadeAccentColor>() }, - uniforms::u_light::Value{ getLight(parameters) }, - uniforms::u_latrange::Value{ getLatRange(id) }, + uniforms::u_matrix::Value( matrix ), + uniforms::u_image::Value( 0 ), + uniforms::u_highlight::Value( evaluated.get<HillshadeHighlightColor>() ), + uniforms::u_shadow::Value( evaluated.get<HillshadeShadowColor>() ), + uniforms::u_accent::Value( evaluated.get<HillshadeAccentColor>() ), + uniforms::u_light::Value( getLight(parameters) ), + uniforms::u_latrange::Value( getLatRange(id) ), }, paintAttributeData, evaluated, @@ -137,11 +141,11 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src const auto allUniformValues = programInstance.computeAllUniformValues( HillshadePrepareProgram::UniformValues { - uniforms::u_matrix::Value { mat }, - uniforms::u_dimension::Value { {{uint16_t(tilesize * 2), uint16_t(tilesize * 2) }} }, - uniforms::u_zoom::Value{ float(tile.id.canonical.z) }, - uniforms::u_maxzoom::Value{ float(maxzoom) }, - uniforms::u_image::Value{ 0 } + uniforms::u_matrix::Value( mat ), + uniforms::u_dimension::Value( {{uint16_t(tilesize * 2), uint16_t(tilesize * 2)}} ), + uniforms::u_zoom::Value( float(tile.id.canonical.z) ), + uniforms::u_maxzoom::Value( float(maxzoom) ), + uniforms::u_image::Value( 0 ) }, paintAttributeData, properties, diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.hpp b/src/mbgl/renderer/layers/render_hillshade_layer.hpp index 13093ee7ef..f88f1cd12f 100644 --- a/src/mbgl/renderer/layers/render_hillshade_layer.hpp +++ b/src/mbgl/renderer/layers/render_hillshade_layer.hpp @@ -15,6 +15,7 @@ public: void transition(const TransitionParameters&) override; void evaluate(const PropertyEvaluationParameters&) override; bool hasTransition() const override; + bool hasCrossfade() const override; void render(PaintParameters&, RenderSource* src) override; diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index f204c909e1..ff8a98c950 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -11,6 +11,7 @@ #include <mbgl/geometry/feature_index.hpp> #include <mbgl/util/math.hpp> #include <mbgl/util/intersection_tests.hpp> +#include <mbgl/tile/geometry_tile.hpp> namespace mbgl { @@ -26,8 +27,17 @@ const style::LineLayer::Impl& RenderLineLayer::impl() const { return static_cast<const style::LineLayer::Impl&>(*baseImpl); } -std::unique_ptr<Bucket> RenderLineLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const { - return std::make_unique<LineBucket>(parameters, layers, impl().layout); +std::unique_ptr<Bucket> RenderLineLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const { + assert(false); // Should be calling createLayout() instead. + return nullptr; +} + +std::unique_ptr<PatternLayout<LineBucket>> +RenderLineLayer::createLayout(const BucketParameters& parameters, + const std::vector<const RenderLayer*>& group, + std::unique_ptr<GeometryTileLayer> layer, + ImageDependencies& imageDependencies) const { + return std::make_unique<PatternLayout<LineBucket>>(parameters, group, std::move(layer), imageDependencies); } void RenderLineLayer::transition(const TransitionParameters& parameters) { @@ -41,7 +51,9 @@ void RenderLineLayer::evaluate(const PropertyEvaluationParameters& parameters) { dashArrayParams.useIntegerZoom = true; evaluated = RenderLinePaintProperties::PossiblyEvaluated( - unevaluated.evaluate(parameters).concat(extra.evaluate(dashArrayParams))); + unevaluated.evaluate(parameters).concat(extra.evaluate(dashArrayParams))); + + crossfade = parameters.getCrossfadeParameters(); passes = (evaluated.get<style::LineOpacity>().constantOr(1.0) > 0 && evaluated.get<style::LineColor>().constantOr(Color::black()).a > 0 @@ -53,6 +65,10 @@ bool RenderLineLayer::hasTransition() const { return unevaluated.hasTransition(); } +bool RenderLineLayer::hasCrossfade() const { + return crossfade.t != 1; +} + void RenderLineLayer::render(PaintParameters& parameters, RenderSource*) { if (parameters.pass == RenderPass::Opaque) { return; @@ -65,11 +81,13 @@ void RenderLineLayer::render(PaintParameters& parameters, RenderSource*) { } LineBucket& bucket = *bucket_; - auto draw = [&] (auto& program, auto&& uniformValues) { + auto draw = [&] (auto& program, auto&& uniformValues, const optional<ImagePosition>& patternPositionA, const optional<ImagePosition>& patternPositionB) { auto& programInstance = program.get(evaluated); const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + paintPropertyBinders.setPatternParameters(patternPositionA, patternPositionB, crossfade); + const auto allUniformValues = programInstance.computeAllUniformValues( std::move(uniformValues), paintPropertyBinders, @@ -115,16 +133,18 @@ void RenderLineLayer::render(PaintParameters& parameters, RenderSource*) { parameters.pixelsToGLUnits, posA, posB, - parameters.lineAtlas.getSize().width)); - - } else if (!evaluated.get<LinePattern>().from.empty()) { - optional<ImagePosition> posA = parameters.imageManager.getPattern(evaluated.get<LinePattern>().from); - optional<ImagePosition> posB = parameters.imageManager.getPattern(evaluated.get<LinePattern>().to); + crossfade, + parameters.lineAtlas.getSize().width), {}, {}); - if (!posA || !posB) - return; + } else if (!unevaluated.get<LinePattern>().isUndefined()) { + const auto linePatternValue = evaluated.get<LinePattern>().constantOr(Faded<std::basic_string<char>>{ "", ""}); + assert(dynamic_cast<GeometryTile*>(&tile.tile)); + GeometryTile& geometryTile = static_cast<GeometryTile&>(tile.tile); + parameters.context.bindTexture(*geometryTile.iconAtlasTexture, 0, gl::TextureFilter::Linear); + const Size texsize = geometryTile.iconAtlasTexture->size; - parameters.imageManager.bind(parameters.context, 0); + optional<ImagePosition> posA = geometryTile.getPattern(linePatternValue.from); + optional<ImagePosition> posB = geometryTile.getPattern(linePatternValue.to); draw(parameters.programs.linePattern, LinePatternProgram::uniformValues( @@ -132,9 +152,11 @@ void RenderLineLayer::render(PaintParameters& parameters, RenderSource*) { tile, parameters.state, parameters.pixelsToGLUnits, - parameters.imageManager.getPixelSize(), + texsize, + crossfade, + parameters.pixelRatio), *posA, - *posB)); + *posB); } else if (!unevaluated.get<LineGradient>().getValue().isUndefined()) { if (!colorRampTexture) { colorRampTexture = parameters.context.createTexture(colorRamp); @@ -146,14 +168,14 @@ void RenderLineLayer::render(PaintParameters& parameters, RenderSource*) { evaluated, tile, parameters.state, - parameters.pixelsToGLUnits)); + parameters.pixelsToGLUnits), {}, {}); } else { draw(parameters.programs.line, LineProgram::uniformValues( evaluated, tile, parameters.state, - parameters.pixelsToGLUnits)); + parameters.pixelsToGLUnits), {}, {}); } } } @@ -240,6 +262,24 @@ void RenderLineLayer::updateColorRamp() { } } +RenderLinePaintProperties::PossiblyEvaluated RenderLineLayer::paintProperties() const { + return RenderLinePaintProperties::PossiblyEvaluated { + evaluated.get<style::LineOpacity>(), + evaluated.get<style::LineColor>(), + evaluated.get<style::LineTranslate>(), + evaluated.get<style::LineTranslateAnchor>(), + evaluated.get<style::LineWidth>(), + evaluated.get<style::LineGapWidth>(), + evaluated.get<style::LineOffset>(), + evaluated.get<style::LineBlur>(), + evaluated.get<style::LineDasharray>(), + evaluated.get<style::LinePattern>(), + evaluated.get<style::LineGradient>(), + evaluated.get<LineFloorwidth>() + + }; +} + float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature, const float zoom) const { float lineWidth = evaluated.get<style::LineWidth>() .evaluate(feature, zoom, style::LineWidth::defaultValue()); diff --git a/src/mbgl/renderer/layers/render_line_layer.hpp b/src/mbgl/renderer/layers/render_line_layer.hpp index 1e0100548a..19ccccfb39 100644 --- a/src/mbgl/renderer/layers/render_line_layer.hpp +++ b/src/mbgl/renderer/layers/render_line_layer.hpp @@ -4,7 +4,8 @@ #include <mbgl/style/layers/line_layer_impl.hpp> #include <mbgl/style/layers/line_layer_properties.hpp> #include <mbgl/programs/uniforms.hpp> -#include <mbgl/util/image.hpp> +#include <mbgl/style/image_impl.hpp> +#include <mbgl/layout/pattern_layout.hpp> namespace mbgl { @@ -16,16 +17,24 @@ class RenderLinePaintProperties : public style::ConcatenateProperties< style::LinePaintProperties, style::Properties<LineFloorwidth>> {}; +class LineBucket; + class RenderLineLayer: public RenderLayer { public: + using StyleLayerImpl = style::LineLayer::Impl; + using PatternProperty = style::LinePattern; + RenderLineLayer(Immutable<style::LineLayer::Impl>); ~RenderLineLayer() final = default; void transition(const TransitionParameters&) override; void evaluate(const PropertyEvaluationParameters&) override; bool hasTransition() const override; + bool hasCrossfade() const override; void render(PaintParameters&, RenderSource*) override; + RenderLinePaintProperties::PossiblyEvaluated paintProperties() const; + bool queryIntersectsFeature( const GeometryCoordinates&, const GeometryTileFeature&, @@ -37,7 +46,10 @@ public: void updateColorRamp(); std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override; - + std::unique_ptr<PatternLayout<LineBucket>> createLayout(const BucketParameters&, + const std::vector<const RenderLayer*>&, + std::unique_ptr<GeometryTileLayer>, + ImageDependencies&) const; // Paint properties style::LinePaintProperties::Unevaluated unevaluated; RenderLinePaintProperties::PossiblyEvaluated evaluated; @@ -46,6 +58,7 @@ public: private: float getLineWidth(const GeometryTileFeature&, const float) const; + CrossfadeParameters crossfade; PremultipliedImage colorRamp; optional<gl::Texture> colorRampTexture; }; diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp index e2524697b5..b8df71b7c1 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.cpp +++ b/src/mbgl/renderer/layers/render_raster_layer.cpp @@ -41,6 +41,10 @@ bool RenderRasterLayer::hasTransition() const { return unevaluated.hasTransition(); } +bool RenderRasterLayer::hasCrossfade() const { + return false; +} + static float saturationFactor(float saturation) { if (saturation > 0) { return 1 - 1 / (1.001 - saturation); @@ -83,19 +87,19 @@ void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source const auto allUniformValues = programInstance.computeAllUniformValues( RasterProgram::UniformValues { - uniforms::u_matrix::Value{ matrix }, - uniforms::u_image0::Value{ 0 }, - uniforms::u_image1::Value{ 1 }, - uniforms::u_opacity::Value{ evaluated.get<RasterOpacity>() }, - uniforms::u_fade_t::Value{ 1 }, - uniforms::u_brightness_low::Value{ evaluated.get<RasterBrightnessMin>() }, - uniforms::u_brightness_high::Value{ evaluated.get<RasterBrightnessMax>() }, - uniforms::u_saturation_factor::Value{ saturationFactor(evaluated.get<RasterSaturation>()) }, - uniforms::u_contrast_factor::Value{ contrastFactor(evaluated.get<RasterContrast>()) }, - uniforms::u_spin_weights::Value{ spinWeights(evaluated.get<RasterHueRotate>()) }, - uniforms::u_buffer_scale::Value{ 1.0f }, - uniforms::u_scale_parent::Value{ 1.0f }, - uniforms::u_tl_parent::Value{ std::array<float, 2> {{ 0.0f, 0.0f }} }, + uniforms::u_matrix::Value( matrix ), + uniforms::u_image0::Value( 0 ), + uniforms::u_image1::Value( 1 ), + uniforms::u_opacity::Value( evaluated.get<RasterOpacity>() ), + uniforms::u_fade_t::Value( 1 ), + uniforms::u_brightness_low::Value( evaluated.get<RasterBrightnessMin>() ), + uniforms::u_brightness_high::Value( evaluated.get<RasterBrightnessMax>() ), + uniforms::u_saturation_factor::Value( saturationFactor(evaluated.get<RasterSaturation>()) ), + uniforms::u_contrast_factor::Value( contrastFactor(evaluated.get<RasterContrast>()) ), + uniforms::u_spin_weights::Value( spinWeights(evaluated.get<RasterHueRotate>()) ), + uniforms::u_buffer_scale::Value( 1.0f ), + uniforms::u_scale_parent::Value( 1.0f ), + uniforms::u_tl_parent::Value( std::array<float, 2> {{ 0.0f, 0.0f }} ), }, paintAttributeData, evaluated, diff --git a/src/mbgl/renderer/layers/render_raster_layer.hpp b/src/mbgl/renderer/layers/render_raster_layer.hpp index 87de316f7c..a8633c4d5e 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.hpp +++ b/src/mbgl/renderer/layers/render_raster_layer.hpp @@ -14,6 +14,7 @@ public: void transition(const TransitionParameters&) override; void evaluate(const PropertyEvaluationParameters&) override; bool hasTransition() const override; + bool hasCrossfade() const override; void render(PaintParameters&, RenderSource*) override; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index f9e4e7c043..cf65e29048 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -69,6 +69,10 @@ bool RenderSymbolLayer::hasTransition() const { return unevaluated.hasTransition(); } +bool RenderSymbolLayer::hasCrossfade() const { + return false; +} + void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { if (parameters.pass == RenderPass::Opaque) { return; @@ -251,9 +255,9 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), CollisionBoxProgram::UniformValues { - uniforms::u_matrix::Value{ tile.matrix }, - uniforms::u_extrude_scale::Value{ extrudeScale }, - uniforms::u_camera_to_center_distance::Value{ parameters.state.getCameraToCenterDistance() } + uniforms::u_matrix::Value( tile.matrix ), + uniforms::u_extrude_scale::Value( extrudeScale ), + uniforms::u_camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() ) }, *bucket.collisionBox.vertexBuffer, *bucket.collisionBox.dynamicVertexBuffer, @@ -285,10 +289,10 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), CollisionCircleProgram::UniformValues { - uniforms::u_matrix::Value{ tile.matrix }, - uniforms::u_extrude_scale::Value{ extrudeScale }, - uniforms::u_overscale_factor::Value{ float(tile.tile.id.overscaleFactor()) }, - uniforms::u_camera_to_center_distance::Value{ parameters.state.getCameraToCenterDistance() } + uniforms::u_matrix::Value( tile.matrix ), + uniforms::u_extrude_scale::Value( extrudeScale ), + uniforms::u_overscale_factor::Value( float(tile.tile.id.overscaleFactor()) ), + uniforms::u_camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() ) }, *bucket.collisionCircle.vertexBuffer, *bucket.collisionCircle.dynamicVertexBuffer, diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp index 5b73b30294..efdcf0e932 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.hpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp @@ -64,6 +64,7 @@ public: void transition(const TransitionParameters&) override; void evaluate(const PropertyEvaluationParameters&) override; bool hasTransition() const override; + bool hasCrossfade() const override; void render(PaintParameters&, RenderSource*) override; style::IconPaintProperties::PossiblyEvaluated iconPaintProperties() const; 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; } diff --git a/src/mbgl/renderer/possibly_evaluated_property_value.hpp b/src/mbgl/renderer/possibly_evaluated_property_value.hpp index f2d265f2f7..353df2ab90 100644 --- a/src/mbgl/renderer/possibly_evaluated_property_value.hpp +++ b/src/mbgl/renderer/possibly_evaluated_property_value.hpp @@ -1,6 +1,7 @@ #pragma once #include <mbgl/style/property_expression.hpp> +#include <mbgl/renderer/cross_faded_property_evaluator.hpp> #include <mbgl/util/interpolate.hpp> #include <mbgl/util/variant.hpp> @@ -57,6 +58,61 @@ public: bool useIntegerZoom; }; +template <class T> +class PossiblyEvaluatedPropertyValue<Faded<T>> { +private: + using Value = variant< + Faded<T>, + style::PropertyExpression<T>>; + + Value value; + +public: + PossiblyEvaluatedPropertyValue() = default; + PossiblyEvaluatedPropertyValue(Value v, bool useIntegerZoom_ = false) + : value(std::move(v)), + useIntegerZoom(useIntegerZoom_) {} + + bool isConstant() const { + return value.template is<Faded<T>>(); + } + + optional<Faded<T>> constant() const { + return value.match( + [&] (const Faded<T>& t) { return optional<Faded<T>>(t); }, + [&] (const auto&) { return optional<Faded<T>>(); }); + } + + Faded<T> constantOr(const Faded<T>& t) const { + return constant().value_or(t); + } + + template <class... Ts> + auto match(Ts&&... ts) const { + return value.match(std::forward<Ts>(ts)...); + } + + template <class Feature> + Faded<T> evaluate(const Feature& feature, float zoom, T defaultValue) const { + return this->match( + [&] (const Faded<T>& constant_) { return constant_; }, + [&] (const style::PropertyExpression<T>& expression) { + if (!expression.isZoomConstant()) { + const T min = expression.evaluate(floor(zoom), feature, defaultValue); + const T max = expression.evaluate(floor(zoom) + 1, feature, defaultValue); + return Faded<T> {min, max}; + } else { + const T evaluated = expression.evaluate(feature, defaultValue); + return Faded<T> {evaluated, evaluated}; + } + } + ); + } + + bool useIntegerZoom; +}; + + namespace util { template <typename T> diff --git a/src/mbgl/renderer/property_evaluation_parameters.hpp b/src/mbgl/renderer/property_evaluation_parameters.hpp index da6a4a0892..0e1c317294 100644 --- a/src/mbgl/renderer/property_evaluation_parameters.hpp +++ b/src/mbgl/renderer/property_evaluation_parameters.hpp @@ -5,6 +5,13 @@ namespace mbgl { +class CrossfadeParameters { +public: + float fromScale; + float toScale; + float t; +}; + class PropertyEvaluationParameters { public: explicit PropertyEvaluationParameters(float z_) @@ -24,6 +31,18 @@ public: defaultFadeDuration(std::move(defaultFadeDuration_)), useIntegerZoom(useIntegerZoom_) {} + CrossfadeParameters getCrossfadeParameters() const { + const float fraction = z - std::floor(z); + const std::chrono::duration<float> d = defaultFadeDuration; + const float t = d != std::chrono::duration<float>::zero() + ? std::min((now - zoomHistory.lastIntegerZoomTime) / d, 1.0f) + : 1.0f; + + return z > zoomHistory.lastIntegerZoom + ? CrossfadeParameters { 2.0f, 1.0f, fraction + (1.0f - fraction) * t } + : CrossfadeParameters { 0.5f, 1.0f, 1 - (1 - t) * fraction }; + } + float z; TimePoint now; ZoomHistory zoomHistory; diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp index 3e2f1d7525..9f327c63e5 100644 --- a/src/mbgl/renderer/render_layer.hpp +++ b/src/mbgl/renderer/render_layer.hpp @@ -40,6 +40,9 @@ public: // Returns true if any paint properties have active transitions. virtual bool hasTransition() const = 0; + // Returns true if the layer has a pattern property and is actively crossfading. + virtual bool hasCrossfade() const = 0; + // Check whether this layer is of the given subtype. template <class T> bool is() const; diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp index 64790938ef..fcd8b77771 100644 --- a/src/mbgl/renderer/render_tile.cpp +++ b/src/mbgl/renderer/render_tile.cpp @@ -103,8 +103,8 @@ void RenderTile::finishRender(PaintParameters& parameters) { tile.debugBucket->segments, program.computeAllUniformValues( DebugProgram::UniformValues { - uniforms::u_matrix::Value{ matrix }, - uniforms::u_color::Value{ Color::white() } + uniforms::u_matrix::Value( matrix ), + uniforms::u_color::Value( Color::white() ) }, paintAttributeData, properties, @@ -124,8 +124,8 @@ void RenderTile::finishRender(PaintParameters& parameters) { tile.debugBucket->segments, program.computeAllUniformValues( DebugProgram::UniformValues { - uniforms::u_matrix::Value{ matrix }, - uniforms::u_color::Value{ Color::black() } + uniforms::u_matrix::Value( matrix ), + uniforms::u_color::Value( Color::black() ) }, paintAttributeData, properties, @@ -147,8 +147,8 @@ void RenderTile::finishRender(PaintParameters& parameters) { parameters.staticData.tileBorderSegments, program.computeAllUniformValues( DebugProgram::UniformValues { - uniforms::u_matrix::Value{ matrix }, - uniforms::u_color::Value{ Color::red() } + uniforms::u_matrix::Value( matrix ), + uniforms::u_color::Value( Color::red() ) }, paintAttributeData, properties, diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index bc39c40796..92d04063ca 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -14,6 +14,7 @@ #include <mbgl/renderer/layers/render_background_layer.hpp> #include <mbgl/renderer/layers/render_custom_layer.hpp> #include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp> +#include <mbgl/renderer/layers/render_fill_layer.hpp> #include <mbgl/renderer/layers/render_heatmap_layer.hpp> #include <mbgl/renderer/layers/render_hillshade_layer.hpp> #include <mbgl/renderer/style_diff.hpp> @@ -195,7 +196,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { } } - if (layerAdded || layerChanged || zoomChanged || layer.hasTransition()) { + if (layerAdded || layerChanged || zoomChanged || layer.hasTransition() || layer.hasCrossfade()) { layer.evaluate(evaluationParameters); } } @@ -512,7 +513,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { parameters.staticData.tileTriangleSegments, program.computeAllUniformValues( ClippingMaskProgram::UniformValues { - uniforms::u_matrix::Value{ parameters.matrixForTile(clipID.first) }, + uniforms::u_matrix::Value( parameters.matrixForTile(clipID.first) ), }, paintAttributeData, properties, diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp index 2ce046a7a0..d4577e787a 100644 --- a/src/mbgl/renderer/sources/render_image_source.cpp +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -71,8 +71,8 @@ void RenderImageSource::finishRender(PaintParameters& parameters) { parameters.staticData.tileBorderSegments, programInstance.computeAllUniformValues( DebugProgram::UniformValues { - uniforms::u_matrix::Value{ matrix }, - uniforms::u_color::Value{ Color::red() } + uniforms::u_matrix::Value( matrix ), + uniforms::u_color::Value( Color::red() ) }, paintAttributeData, properties, |