Enable 'circle-sort-key' layout property
This commit is contained in:
committed by
Mikhail Pozdnyakov
parent
08ad742164
commit
0c95acf103
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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 |
@@ -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",
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
165
src/mbgl/layout/circle_layout.hpp
Normal file
165
src/mbgl/layout/circle_layout.hpp
Normal 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
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user