Enable 'circle-sort-key' layout property

This commit is contained in:
Andrew Hay Kurtz
2019-10-29 13:49:22 -07:00
committed by Mikhail Pozdnyakov
parent 08ad742164
commit 0c95acf103
18 changed files with 353 additions and 104 deletions

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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();

Binary file not shown.

After

Width:  |  Height:  |  Size: 950 B

View File

@@ -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",

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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

View File

@@ -70,6 +70,47 @@ public:
return allAttributeBindings.activeCount();
}
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 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,

View File

@@ -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);

View File

@@ -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;

View File

@@ -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());
}
}
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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,

View File

@@ -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')

View File

@@ -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());