diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | include/mbgl/layermanager/circle_layer_factory.hpp | 4 | ||||
-rw-r--r-- | include/mbgl/style/layers/circle_layer.hpp | 6 | ||||
-rw-r--r-- | metrics/expectations/platform-all/render-tests/circle-sort-key/literal/expected.png | bin | 0 -> 950 bytes | |||
-rw-r--r-- | metrics/ignores/platform-all.json | 1 | ||||
-rwxr-xr-x | scripts/generate-style-code.js | 3 | ||||
-rw-r--r-- | src/mbgl/layermanager/circle_layer_factory.cpp | 8 | ||||
-rw-r--r-- | src/mbgl/layout/circle_layout.hpp | 165 | ||||
-rw-r--r-- | src/mbgl/programs/program.hpp | 41 | ||||
-rw-r--r-- | src/mbgl/renderer/buckets/circle_bucket.cpp | 74 | ||||
-rw-r--r-- | src/mbgl/renderer/buckets/circle_bucket.hpp | 13 | ||||
-rw-r--r-- | src/mbgl/renderer/layers/render_circle_layer.cpp | 82 | ||||
-rw-r--r-- | src/mbgl/style/layers/circle_layer.cpp | 34 | ||||
-rw-r--r-- | src/mbgl/style/layers/circle_layer_impl.cpp | 3 | ||||
-rw-r--r-- | src/mbgl/style/layers/circle_layer_impl.hpp | 1 | ||||
-rw-r--r-- | src/mbgl/style/layers/circle_layer_properties.hpp | 9 | ||||
-rw-r--r-- | src/mbgl/style/layers/layer.cpp.ejs | 5 | ||||
-rw-r--r-- | test/gl/bucket.test.cpp | 7 |
18 files changed, 353 insertions, 104 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index c024d7f6cb..583c3df593 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -341,6 +341,7 @@ add_library( ${PROJECT_SOURCE_DIR}/src/mbgl/layermanager/line_layer_factory.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/layermanager/raster_layer_factory.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/layermanager/symbol_layer_factory.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/layout/circle_layout.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/layout/clip_lines.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/layout/clip_lines.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/layout/layout.hpp diff --git a/include/mbgl/layermanager/circle_layer_factory.hpp b/include/mbgl/layermanager/circle_layer_factory.hpp index 51135d3383..aaf5fddfb6 100644 --- a/include/mbgl/layermanager/circle_layer_factory.hpp +++ b/include/mbgl/layermanager/circle_layer_factory.hpp @@ -8,7 +8,9 @@ class CircleLayerFactory : public LayerFactory { protected: const style::LayerTypeInfo* getTypeInfo() const noexcept final; std::unique_ptr<style::Layer> createLayer(const std::string& id, const style::conversion::Convertible& value) noexcept final; - std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<Immutable<style::LayerProperties>>&) noexcept final; + std::unique_ptr<Layout> createLayout(const LayoutParameters& parameters, + std::unique_ptr<GeometryTileLayer> tileLayer, + const std::vector<Immutable<style::LayerProperties>>& group) noexcept final; std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept final; }; diff --git a/include/mbgl/style/layers/circle_layer.hpp b/include/mbgl/style/layers/circle_layer.hpp index f0e9787caa..aac02121e1 100644 --- a/include/mbgl/style/layers/circle_layer.hpp +++ b/include/mbgl/style/layers/circle_layer.hpp @@ -19,6 +19,12 @@ public: CircleLayer(const std::string& layerID, const std::string& sourceID); ~CircleLayer() final; + // Layout properties + + static PropertyValue<float> getDefaultCircleSortKey(); + const PropertyValue<float>& getCircleSortKey() const; + void setCircleSortKey(const PropertyValue<float>&); + // Paint properties static PropertyValue<float> getDefaultCircleBlur(); diff --git a/metrics/expectations/platform-all/render-tests/circle-sort-key/literal/expected.png b/metrics/expectations/platform-all/render-tests/circle-sort-key/literal/expected.png Binary files differnew file mode 100644 index 0000000000..78c42d43f0 --- /dev/null +++ b/metrics/expectations/platform-all/render-tests/circle-sort-key/literal/expected.png diff --git a/metrics/ignores/platform-all.json b/metrics/ignores/platform-all.json index 9e20b2ffc5..da53a7a559 100644 --- a/metrics/ignores/platform-all.json +++ b/metrics/ignores/platform-all.json @@ -55,7 +55,6 @@ "render-tests/background-color/transition": "https://github.com/mapbox/mapbox-gl-native/issues/10619", "render-tests/canvas/default": "skip - js specific", "render-tests/canvas/update": "skip - js specific", - "render-tests/circle-sort-key/literal": "https://github.com/mapbox/mapbox-gl-native/issues/15008", "render-tests/collator/default": "Some test platforms don't resolve 'en' locale", "render-tests/collator/resolved-locale": "Some test platforms don't resolve 'en' locale", "render-tests/custom-layer-js/depth": "skip - js specific", diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index c9191d59e1..de70fdcbe8 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -6,9 +6,6 @@ const ejs = require('ejs'); const spec = require('./style-spec'); const colorParser = require('csscolorparser'); -// FIXME: https://github.com/mapbox/mapbox-gl-native/issues/15008 -delete spec.layout_circle["circle-sort-key"] - require('./style-code'); function parseCSSColor(str) { diff --git a/src/mbgl/layermanager/circle_layer_factory.cpp b/src/mbgl/layermanager/circle_layer_factory.cpp index ce28270c0b..5bde1ede8b 100644 --- a/src/mbgl/layermanager/circle_layer_factory.cpp +++ b/src/mbgl/layermanager/circle_layer_factory.cpp @@ -1,5 +1,6 @@ #include <mbgl/layermanager/circle_layer_factory.hpp> +#include <mbgl/layout/circle_layout.hpp> #include <mbgl/renderer/buckets/circle_bucket.hpp> #include <mbgl/renderer/layers/render_circle_layer.hpp> #include <mbgl/style/layers/circle_layer.hpp> @@ -20,8 +21,11 @@ std::unique_ptr<style::Layer> CircleLayerFactory::createLayer(const std::string& return std::unique_ptr<style::Layer>(new style::CircleLayer(id, *source)); } -std::unique_ptr<Bucket> CircleLayerFactory::createBucket(const BucketParameters& parameters, const std::vector<Immutable<style::LayerProperties>>& layers) noexcept { - return std::make_unique<CircleBucket>(parameters, layers); +std::unique_ptr<Layout> CircleLayerFactory::createLayout( + const LayoutParameters& parameters, + std::unique_ptr<GeometryTileLayer> layer, + const std::vector<Immutable<style::LayerProperties>>& group) noexcept { + return std::make_unique<CircleLayout>(parameters.bucketParameters, group, std::move(layer)); } std::unique_ptr<RenderLayer> CircleLayerFactory::createRenderLayer(Immutable<style::Layer::Impl> impl) noexcept { diff --git a/src/mbgl/layout/circle_layout.hpp b/src/mbgl/layout/circle_layout.hpp new file mode 100644 index 0000000000..0f4f1d0328 --- /dev/null +++ b/src/mbgl/layout/circle_layout.hpp @@ -0,0 +1,165 @@ +#pragma once +#include <mbgl/geometry/feature_index.hpp> +#include <mbgl/layout/layout.hpp> +#include <mbgl/renderer/bucket_parameters.hpp> +#include <mbgl/renderer/buckets/circle_bucket.hpp> +#include <mbgl/renderer/render_layer.hpp> +#include <mbgl/style/layers/circle_layer_impl.hpp> + +namespace mbgl { + +class CircleFeature { +public: + friend bool operator<(const CircleFeature& lhs, const CircleFeature& rhs) { return lhs.sortKey < rhs.sortKey; } + + size_t i; + std::unique_ptr<GeometryTileFeature> feature; + float sortKey; +}; + +class CircleLayout : public Layout { +public: + CircleLayout(const BucketParameters& parameters, + const std::vector<Immutable<style::LayerProperties>>& group, + std::unique_ptr<GeometryTileLayer> sourceLayer_) + : sourceLayer(std::move(sourceLayer_)), + zoom(parameters.tileID.overscaledZ), + mode(parameters.mode), + hasPattern(false) { + assert(!group.empty()); + auto leaderLayerProperties = staticImmutableCast<style::CircleLayerProperties>(group.front()); + unevaluatedLayout = leaderLayerProperties->layerImpl().layout; + layout = unevaluatedLayout.evaluate(PropertyEvaluationParameters(zoom)); + sourceLayerID = leaderLayerProperties->layerImpl().sourceLayer; + bucketLeaderID = leaderLayerProperties->layerImpl().id; + + for (const auto& layerProperties : group) { + const std::string& layerId = layerProperties->baseImpl->id; + layerPropertiesMap.emplace(layerId, layerProperties); + } + + const size_t featureCount = sourceLayer->featureCount(); + for (size_t i = 0; i < featureCount; ++i) { + auto feature = sourceLayer->getFeature(i); + if (!leaderLayerProperties->layerImpl().filter( + style::expression::EvaluationContext{this->zoom, feature.get()})) + continue; + + auto sortKey = evaluateSortKey(*feature); + + CircleFeature circleFeature{i, std::move(feature), sortKey}; + const auto sortPosition = std::lower_bound(features.cbegin(), features.cend(), circleFeature); + features.insert(sortPosition, std::move(circleFeature)); + } + }; + + ~CircleLayout() final = default; + + bool hasDependencies() const override { return hasPattern; } + + void createBucket(const ImagePositions&, + std::unique_ptr<FeatureIndex>& featureIndex, + std::unordered_map<std::string, LayerRenderData>& renderData, + const bool, + const bool, + const CanonicalTileID& canonical) override { + auto bucket = std::make_shared<CircleBucket>(layerPropertiesMap, mode, zoom); + + for (auto& circleFeature : features) { + const auto i = circleFeature.i; + std::unique_ptr<GeometryTileFeature> feature = std::move(circleFeature.feature); + const GeometryCollection& geometries = feature->getGeometries(); + + addCircle(*bucket, *feature, geometries, i, circleFeature.sortKey, canonical); + featureIndex->insert(geometries, i, sourceLayerID, bucketLeaderID); + } + if (bucket->hasData()) { + for (const auto& pair : layerPropertiesMap) { + renderData.emplace(pair.first, LayerRenderData{bucket, pair.second}); + } + } + }; + +private: + void addCircle(CircleBucket& bucket, + const GeometryTileFeature& feature, + const GeometryCollection& geometry, + std::size_t featureIndex, + float sortKey, + const CanonicalTileID& canonical) { + constexpr const uint16_t vertexLength = 4; + + auto& segments = bucket.segments; + auto& vertices = bucket.vertices; + auto& triangles = bucket.triangles; + + for (auto& circle : geometry) { + for (auto& point : circle) { + auto x = point.x; + auto y = point.y; + + // Do not include points that are outside the tile boundaries. + // Include all points in Still mode. You need to include points from + // neighbouring tiles so that they are not clipped at tile boundaries. + if ((mode == MapMode::Continuous) && (x < 0 || x >= util::EXTENT || y < 0 || y >= util::EXTENT)) + continue; + + if (segments.empty() || + segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) { + // Move to a new segments because the old one can't hold the geometry. + segments.emplace_back(vertices.elements(), triangles.elements(), 0ul, 0ul, sortKey); + } + + // this geometry will be of the Point type, and we'll derive + // two triangles from it. + // + // ┌─────────┐ + // │ 4 3 │ + // │ │ + // │ 1 2 │ + // └─────────┘ + // + vertices.emplace_back(CircleProgram::vertex(point, -1, -1)); // 1 + vertices.emplace_back(CircleProgram::vertex(point, 1, -1)); // 2 + vertices.emplace_back(CircleProgram::vertex(point, 1, 1)); // 3 + vertices.emplace_back(CircleProgram::vertex(point, -1, 1)); // 4 + + auto& segment = segments.back(); + assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max()); + uint16_t index = segment.vertexLength; + + // 1, 2, 3 + // 1, 4, 3 + triangles.emplace_back(index, index + 1, index + 2); + triangles.emplace_back(index, index + 3, index + 2); + + segment.vertexLength += vertexLength; + segment.indexLength += 6; + } + } + + for (auto& pair : bucket.paintPropertyBinders) { + pair.second.populateVertexVectors(feature, vertices.elements(), featureIndex, {}, {}, canonical); + } + } + + float evaluateSortKey(const GeometryTileFeature& sourceFeature) { + const auto sortKeyProperty = layout.template get<style::CircleSortKey>(); + return sortKeyProperty.evaluate(sourceFeature, zoom, style::CircleSortKey::defaultValue()); + } + + std::map<std::string, Immutable<style::LayerProperties>> layerPropertiesMap; + std::string bucketLeaderID; + + const std::unique_ptr<GeometryTileLayer> sourceLayer; + std::list<CircleFeature> features; + typename style::CircleLayoutProperties::Unevaluated unevaluatedLayout; + typename style::CircleLayoutProperties::PossiblyEvaluated layout; + + const float zoom; + const MapMode mode; + std::string sourceLayerID; + bool hasPattern; +}; + +} // namespace mbgl diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp index ae9d1d3669..9f833a774d 100644 --- a/src/mbgl/programs/program.hpp +++ b/src/mbgl/programs/program.hpp @@ -79,6 +79,47 @@ public: const gfx::ColorMode& colorMode, const gfx::CullFaceMode& cullFaceMode, const gfx::IndexBuffer& indexBuffer, + const Segment<AttributeList>& segment, + const UniformValues& uniformValues, + const AttributeBindings& allAttributeBindings, + const TextureBindings& textureBindings, + const std::string& layerID) { + static_assert(Primitive == gfx::PrimitiveTypeOf<DrawMode>::value, "incompatible draw mode"); + + if (!program) { + return; + } + + auto drawScopeIt = segment.drawScopes.find(layerID); + if (drawScopeIt == segment.drawScopes.end()) { + drawScopeIt = segment.drawScopes.emplace(layerID, context.createDrawScope()).first; + } + + program->draw(context, + renderPass, + drawMode, + depthMode, + stencilMode, + colorMode, + cullFaceMode, + uniformValues, + drawScopeIt->second, + allAttributeBindings.offset(segment.vertexOffset), + textureBindings, + indexBuffer, + segment.indexOffset, + segment.indexLength); + } + + template <class DrawMode> + void draw(gfx::Context& context, + gfx::RenderPass& renderPass, + const DrawMode& drawMode, + const gfx::DepthMode& depthMode, + const gfx::StencilMode& stencilMode, + const gfx::ColorMode& colorMode, + const gfx::CullFaceMode& cullFaceMode, + const gfx::IndexBuffer& indexBuffer, const SegmentVector<AttributeList>& segments, const UniformValues& uniformValues, const AttributeBindings& allAttributeBindings, diff --git a/src/mbgl/renderer/buckets/circle_bucket.cpp b/src/mbgl/renderer/buckets/circle_bucket.cpp index 744b559c42..5a1184f5fd 100644 --- a/src/mbgl/renderer/buckets/circle_bucket.cpp +++ b/src/mbgl/renderer/buckets/circle_bucket.cpp @@ -10,15 +10,14 @@ namespace mbgl { using namespace style; -CircleBucket::CircleBucket(const BucketParameters& parameters, const std::vector<Immutable<style::LayerProperties>>& layers) - : mode(parameters.mode) { - for (const auto& layer : layers) { - paintPropertyBinders.emplace( - std::piecewise_construct, - std::forward_as_tuple(layer->baseImpl->id), - std::forward_as_tuple( - getEvaluated<CircleLayerProperties>(layer), - parameters.tileID.overscaledZ)); +CircleBucket::CircleBucket(const std::map<std::string, Immutable<LayerProperties>>& layerPaintProperties, + const MapMode mode_, + const float zoom) + : mode(mode_) { + for (const auto& pair : layerPaintProperties) { + paintPropertyBinders.emplace(std::piecewise_construct, + std::forward_as_tuple(pair.first), + std::forward_as_tuple(getEvaluated<CircleLayerProperties>(pair.second), zoom)); } } @@ -41,63 +40,6 @@ bool CircleBucket::hasData() const { return !segments.empty(); } -void CircleBucket::addFeature(const GeometryTileFeature& feature, - const GeometryCollection& geometry, - const ImagePositions&, - const PatternLayerMap&, - std::size_t featureIndex, - const CanonicalTileID& canonical) { - constexpr const uint16_t vertexLength = 4; - - for (auto& circle : geometry) { - for(auto& point : circle) { - auto x = point.x; - auto y = point.y; - - // Do not include points that are outside the tile boundaries. - // Include all points in Still mode. You need to include points from - // neighbouring tiles so that they are not clipped at tile boundaries. - if ((mode == MapMode::Continuous) && - (x < 0 || x >= util::EXTENT || y < 0 || y >= util::EXTENT)) continue; - - if (segments.empty() || segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) { - // Move to a new segments because the old one can't hold the geometry. - segments.emplace_back(vertices.elements(), triangles.elements()); - } - - // this geometry will be of the Point type, and we'll derive - // two triangles from it. - // - // ┌─────────┐ - // │ 4 3 │ - // │ │ - // │ 1 2 │ - // └─────────┘ - // - vertices.emplace_back(CircleProgram::vertex(point, -1, -1)); // 1 - vertices.emplace_back(CircleProgram::vertex(point, 1, -1)); // 2 - vertices.emplace_back(CircleProgram::vertex(point, 1, 1)); // 3 - vertices.emplace_back(CircleProgram::vertex(point, -1, 1)); // 4 - - auto& segment = segments.back(); - assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max()); - uint16_t index = segment.vertexLength; - - // 1, 2, 3 - // 1, 4, 3 - triangles.emplace_back(index, index + 1, index + 2); - triangles.emplace_back(index, index + 3, index + 2); - - segment.vertexLength += vertexLength; - segment.indexLength += 6; - } - } - - for (auto& pair : paintPropertyBinders) { - pair.second.populateVertexVectors(feature, vertices.elements(), featureIndex, {}, {}, canonical); - } -} - template <class Property> static float get(const CirclePaintProperties::PossiblyEvaluated& evaluated, const std::string& id, const std::map<std::string, CircleProgram::Binders>& paintPropertyBinders) { auto it = paintPropertyBinders.find(id); diff --git a/src/mbgl/renderer/buckets/circle_bucket.hpp b/src/mbgl/renderer/buckets/circle_bucket.hpp index 17ddd9dc10..221deb5f17 100644 --- a/src/mbgl/renderer/buckets/circle_bucket.hpp +++ b/src/mbgl/renderer/buckets/circle_bucket.hpp @@ -15,15 +15,12 @@ class BucketParameters; class CircleBucket final : public Bucket { public: - CircleBucket(const BucketParameters&, const std::vector<Immutable<style::LayerProperties>>&); - ~CircleBucket() override; + using PossiblyEvaluatedLayoutProperties = style::CircleLayoutProperties::PossiblyEvaluated; - void addFeature(const GeometryTileFeature&, - const GeometryCollection&, - const ImagePositions&, - const PatternLayerMap&, - std::size_t, - const CanonicalTileID&) override; + CircleBucket(const std::map<std::string, Immutable<style::LayerProperties>>& layerPaintProperties, + const MapMode mode, + const float zoom); + ~CircleBucket() override; bool hasData() const override; diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index a8a70d2a3a..a85b82b2d2 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -17,6 +17,32 @@ using namespace style; namespace { +struct RenderableSegment { + RenderableSegment(const Segment<CircleAttributes>& segment_, + CircleProgram& programInstance_, + const CircleBucket& bucket_, + const CircleProgram::UniformValues& allUniformValues_, + const CircleProgram::AttributeBindings& allAttributeBindings_, + float sortKey_) + : segment(segment_), + programInstance(programInstance_), + bucket(bucket_), + allUniformValues(allUniformValues_), + allAttributeBindings(allAttributeBindings_), + sortKey(sortKey_) {} + + const Segment<CircleAttributes>& segment; + CircleProgram& programInstance; + const CircleBucket& bucket; + const CircleProgram::UniformValues& allUniformValues; + const CircleProgram::AttributeBindings& allAttributeBindings; + const float sortKey; + + friend bool operator<(const RenderableSegment& lhs, const RenderableSegment& rhs) { + return lhs.sortKey < rhs.sortKey; + } +}; + inline const style::CircleLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& impl) { assert(impl->getTypeInfo() == CircleLayer::Impl::staticTypeInfo()); return static_cast<const style::CircleLayer::Impl&>(*impl); @@ -63,6 +89,9 @@ void RenderCircleLayer::render(PaintParameters& parameters) { return; } + const bool sortFeaturesByKey = !impl_cast(baseImpl).layout.get<CircleSortKey>().isUndefined(); + std::multiset<RenderableSegment> renderableSegments{}; + for (const RenderTile& tile : *renderTiles) { const LayerRenderData* renderData = getRenderDataForPass(tile, parameters.pass); if (!renderData) { @@ -96,21 +125,44 @@ void RenderCircleLayer::render(PaintParameters& parameters) { checkRenderability(parameters, CircleProgram::activeBindingCount(allAttributeBindings)); - programInstance.draw( - parameters.context, - *parameters.renderPass, - gfx::Triangles(), - parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly), - gfx::StencilMode::disabled(), - parameters.colorModeForRenderPass(), - gfx::CullFaceMode::disabled(), - *bucket.indexBuffer, - bucket.segments, - allUniformValues, - allAttributeBindings, - CircleProgram::TextureBindings{}, - getID() - ); + if (sortFeaturesByKey) { + for (auto& segment : bucket.segments) { + renderableSegments.emplace( + segment, programInstance, bucket, allUniformValues, allAttributeBindings, segment.sortKey); + } + } else { + programInstance.draw(parameters.context, + *parameters.renderPass, + gfx::Triangles(), + parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly), + gfx::StencilMode::disabled(), + parameters.colorModeForRenderPass(), + gfx::CullFaceMode::disabled(), + *bucket.indexBuffer, + bucket.segments, + allUniformValues, + allAttributeBindings, + CircleProgram::TextureBindings{}, + getID()); + } + } + + if (sortFeaturesByKey) { + for (const auto& renderable : renderableSegments) { + renderable.programInstance.draw(parameters.context, + *parameters.renderPass, + gfx::Triangles(), + parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly), + gfx::StencilMode::disabled(), + parameters.colorModeForRenderPass(), + gfx::CullFaceMode::disabled(), + *renderable.bucket.indexBuffer, + renderable.segment, + renderable.allUniformValues, + renderable.allAttributeBindings, + CircleProgram::TextureBindings{}, + getID()); + } } } diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index ad34ba8223..bf415ea42d 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -24,7 +24,7 @@ const LayerTypeInfo* CircleLayer::Impl::staticTypeInfo() noexcept { const static LayerTypeInfo typeInfo{"circle", LayerTypeInfo::Source::Required, LayerTypeInfo::Pass3D::NotRequired, - LayerTypeInfo::Layout::NotRequired, + LayerTypeInfo::Layout::Required, LayerTypeInfo::FadingTiles::NotRequired, LayerTypeInfo::CrossTileIndex::NotRequired, LayerTypeInfo::TileKind::Geometry}; @@ -57,11 +57,27 @@ std::unique_ptr<Layer> CircleLayer::cloneRef(const std::string& id_) const { return std::make_unique<CircleLayer>(std::move(impl_)); } -void CircleLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const { +void CircleLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>& writer) const { + layout.stringify(writer); } // Layout properties +PropertyValue<float> CircleLayer::getDefaultCircleSortKey() { + return CircleSortKey::defaultValue(); +} + +const PropertyValue<float>& CircleLayer::getCircleSortKey() const { + return impl().layout.get<CircleSortKey>(); +} + +void CircleLayer::setCircleSortKey(const PropertyValue<float>& value) { + if (value == getCircleSortKey()) return; + auto impl_ = mutableImpl(); + impl_->layout.get<CircleSortKey>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} // Paint properties @@ -391,6 +407,7 @@ enum class Property : uint8_t { CircleStrokeWidthTransition, CircleTranslateTransition, CircleTranslateAnchorTransition, + CircleSortKey = kPaintPropertyCount, }; template <typename T> @@ -420,7 +437,8 @@ MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map< {"circle-stroke-opacity-transition", toUint8(Property::CircleStrokeOpacityTransition)}, {"circle-stroke-width-transition", toUint8(Property::CircleStrokeWidthTransition)}, {"circle-translate-transition", toUint8(Property::CircleTranslateTransition)}, - {"circle-translate-anchor-transition", toUint8(Property::CircleTranslateAnchorTransition)}}); + {"circle-translate-anchor-transition", toUint8(Property::CircleTranslateAnchorTransition)}, + {"circle-sort-key", toUint8(Property::CircleSortKey)}}); StyleProperty getLayerProperty(const CircleLayer& layer, Property property) { switch (property) { @@ -468,6 +486,8 @@ StyleProperty getLayerProperty(const CircleLayer& layer, Property property) { return makeStyleProperty(layer.getCircleTranslateTransition()); case Property::CircleTranslateAnchorTransition: return makeStyleProperty(layer.getCircleTranslateAnchorTransition()); + case Property::CircleSortKey: + return makeStyleProperty(layer.getCircleSortKey()); } return {}; } @@ -500,7 +520,8 @@ optional<Error> CircleLayer::setPropertyInternal(const std::string& name, const auto property = static_cast<Property>(it->second); if (property == Property::CircleBlur || property == Property::CircleOpacity || property == Property::CircleRadius || - property == Property::CircleStrokeOpacity || property == Property::CircleStrokeWidth) { + property == Property::CircleStrokeOpacity || property == Property::CircleStrokeWidth || + property == Property::CircleSortKey) { Error error; const auto& typedValue = convert<PropertyValue<float>>(value, error, true, false); if (!typedValue) { @@ -531,6 +552,11 @@ optional<Error> CircleLayer::setPropertyInternal(const std::string& name, const setCircleStrokeWidth(*typedValue); return nullopt; } + + if (property == Property::CircleSortKey) { + setCircleSortKey(*typedValue); + return nullopt; + } } if (property == Property::CircleColor || property == Property::CircleStrokeColor) { Error error; diff --git a/src/mbgl/style/layers/circle_layer_impl.cpp b/src/mbgl/style/layers/circle_layer_impl.cpp index bf0688ac8b..d40cc4bf9a 100644 --- a/src/mbgl/style/layers/circle_layer_impl.cpp +++ b/src/mbgl/style/layers/circle_layer_impl.cpp @@ -6,8 +6,7 @@ namespace style { bool CircleLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const { assert(other.getTypeInfo() == getTypeInfo()); const auto& impl = static_cast<const style::CircleLayer::Impl&>(other); - return filter != impl.filter || - visibility != impl.visibility || + return filter != impl.filter || visibility != impl.visibility || layout != impl.layout || paint.hasDataDrivenPropertyDifference(impl.paint); } diff --git a/src/mbgl/style/layers/circle_layer_impl.hpp b/src/mbgl/style/layers/circle_layer_impl.hpp index 9b3ce48706..4826e58a63 100644 --- a/src/mbgl/style/layers/circle_layer_impl.hpp +++ b/src/mbgl/style/layers/circle_layer_impl.hpp @@ -14,6 +14,7 @@ public: bool hasLayoutDifference(const Layer::Impl&) const override; void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; + CircleLayoutProperties::Unevaluated layout; CirclePaintProperties::Transitionable paint; DECLARE_LAYER_TYPE_INFO; diff --git a/src/mbgl/style/layers/circle_layer_properties.hpp b/src/mbgl/style/layers/circle_layer_properties.hpp index 5204421d0b..c8ec81eed5 100644 --- a/src/mbgl/style/layers/circle_layer_properties.hpp +++ b/src/mbgl/style/layers/circle_layer_properties.hpp @@ -16,6 +16,11 @@ namespace mbgl { namespace style { +struct CircleSortKey : DataDrivenLayoutProperty<float> { + static constexpr const char *name() { return "circle-sort-key"; } + static float defaultValue() { return 0; } +}; + struct CircleBlur : DataDrivenPaintProperty<float, attributes::blur, uniforms::blur> { static float defaultValue() { return 0; } }; @@ -60,6 +65,10 @@ struct CircleTranslateAnchor : PaintProperty<TranslateAnchorType> { static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; } }; +class CircleLayoutProperties : public Properties< + CircleSortKey +> {}; + class CirclePaintProperties : public Properties< CircleBlur, CircleColor, diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index fd5bf619f7..8fd4b1fef0 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -73,7 +73,10 @@ layerCapabilities['symbol'] = defaults.require('Source') .require('CrossTileIndex') .set('TileKind', 'Geometry') .finalize(); -layerCapabilities['circle'] = defaults.require('Source').set('TileKind', 'Geometry').finalize(); +layerCapabilities['circle'] = defaults.require('Source') + .require('Layout') + .set('TileKind', 'Geometry') + .finalize(); layerCapabilities['line'] = layerCapabilities['fill']; layerCapabilities['heatmap'] = defaults.require('Source') .require('Pass3D') diff --git a/test/gl/bucket.test.cpp b/test/gl/bucket.test.cpp index 9f780fcffa..fd8644bfbc 100644 --- a/test/gl/bucket.test.cpp +++ b/test/gl/bucket.test.cpp @@ -47,10 +47,11 @@ TEST(Buckets, CircleBucket) { gfx::BackendScope scope { backend }; gl::Context context{ backend }; - CircleBucket bucket { { {0, 0, 0}, MapMode::Static, 1.0, nullptr }, {} }; + CircleBucket bucket{{}, MapMode::Static, 1.0}; ASSERT_FALSE(bucket.hasData()); ASSERT_FALSE(bucket.needsUpload()); + // CircleBucket::addFeature() is a no-op. GeometryCollection point { { { 0, 0 } } }; bucket.addFeature(StubGeometryTileFeature{{}, FeatureType::Point, point, properties}, point, @@ -58,6 +59,10 @@ TEST(Buckets, CircleBucket) { PatternLayerMap(), 0, CanonicalTileID(0, 0, 0)); + ASSERT_FALSE(bucket.hasData()); + ASSERT_FALSE(bucket.needsUpload()); + + bucket.segments.emplace_back(0, 0); ASSERT_TRUE(bucket.hasData()); ASSERT_TRUE(bucket.needsUpload()); |