1 #include <mbgl/renderer/buckets/circle_bucket.hpp>
2 #include <mbgl/renderer/bucket_parameters.hpp>
3 #include <mbgl/programs/circle_program.hpp>
4 #include <mbgl/style/layers/circle_layer_impl.hpp>
5 #include <mbgl/renderer/layers/render_circle_layer.hpp>
6 #include <mbgl/util/constants.hpp>
7 #include <mbgl/util/math.hpp>
8 
9 namespace mbgl {
10 
11 using namespace style;
12 
CircleBucket(const BucketParameters & parameters,const std::vector<const RenderLayer * > & layers)13 CircleBucket::CircleBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers)
14     : Bucket(LayerType::Circle),
15       mode(parameters.mode) {
16     for (const auto& layer : layers) {
17         paintPropertyBinders.emplace(
18             std::piecewise_construct,
19             std::forward_as_tuple(layer->getID()),
20             std::forward_as_tuple(
21                 layer->as<RenderCircleLayer>()->evaluated,
22                 parameters.tileID.overscaledZ));
23     }
24 }
25 
upload(gl::Context & context)26 void CircleBucket::upload(gl::Context& context) {
27     vertexBuffer = context.createVertexBuffer(std::move(vertices));
28     indexBuffer = context.createIndexBuffer(std::move(triangles));
29 
30     for (auto& pair : paintPropertyBinders) {
31         pair.second.upload(context);
32     }
33 
34     uploaded = true;
35 }
36 
hasData() const37 bool CircleBucket::hasData() const {
38     return !segments.empty();
39 }
40 
addFeature(const GeometryTileFeature & feature,const GeometryCollection & geometry)41 void CircleBucket::addFeature(const GeometryTileFeature& feature,
42                               const GeometryCollection& geometry) {
43     constexpr const uint16_t vertexLength = 4;
44 
45     for (auto& circle : geometry) {
46         for(auto& point : circle) {
47             auto x = point.x;
48             auto y = point.y;
49 
50             // Do not include points that are outside the tile boundaries.
51             // Include all points in Still mode. You need to include points from
52             // neighbouring tiles so that they are not clipped at tile boundaries.
53             if ((mode == MapMode::Continuous) &&
54                 (x < 0 || x >= util::EXTENT || y < 0 || y >= util::EXTENT)) continue;
55 
56             if (segments.empty() || segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) {
57                 // Move to a new segments because the old one can't hold the geometry.
58                 segments.emplace_back(vertices.vertexSize(), triangles.indexSize());
59             }
60 
61             // this geometry will be of the Point type, and we'll derive
62             // two triangles from it.
63             //
64             // ┌─────────┐
65             // │ 4     3 │
66             // │         │
67             // │ 1     2 │
68             // └─────────┘
69             //
70             vertices.emplace_back(CircleProgram::vertex(point, -1, -1)); // 1
71             vertices.emplace_back(CircleProgram::vertex(point,  1, -1)); // 2
72             vertices.emplace_back(CircleProgram::vertex(point,  1,  1)); // 3
73             vertices.emplace_back(CircleProgram::vertex(point, -1,  1)); // 4
74 
75             auto& segment = segments.back();
76             assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max());
77             uint16_t index = segment.vertexLength;
78 
79             // 1, 2, 3
80             // 1, 4, 3
81             triangles.emplace_back(index, index + 1, index + 2);
82             triangles.emplace_back(index, index + 3, index + 2);
83 
84             segment.vertexLength += vertexLength;
85             segment.indexLength += 6;
86         }
87     }
88 
89     for (auto& pair : paintPropertyBinders) {
90         pair.second.populateVertexVectors(feature, vertices.vertexSize());
91     }
92 }
93 
94 template <class Property>
get(const RenderCircleLayer & layer,const std::map<std::string,CircleProgram::PaintPropertyBinders> & paintPropertyBinders)95 static float get(const RenderCircleLayer& layer, const std::map<std::string, CircleProgram::PaintPropertyBinders>& paintPropertyBinders) {
96     auto it = paintPropertyBinders.find(layer.getID());
97     if (it == paintPropertyBinders.end() || !it->second.statistics<Property>().max()) {
98         return layer.evaluated.get<Property>().constantOr(Property::defaultValue());
99     } else {
100         return *it->second.statistics<Property>().max();
101     }
102 }
103 
getQueryRadius(const RenderLayer & layer) const104 float CircleBucket::getQueryRadius(const RenderLayer& layer) const {
105     if (!layer.is<RenderCircleLayer>()) {
106         return 0;
107     }
108 
109     auto circleLayer = layer.as<RenderCircleLayer>();
110 
111     float radius = get<CircleRadius>(*circleLayer, paintPropertyBinders);
112     float stroke = get<CircleStrokeWidth>(*circleLayer, paintPropertyBinders);
113     auto translate = circleLayer->evaluated.get<CircleTranslate>();
114     return radius + stroke + util::length(translate[0], translate[1]);
115 }
116 
117 } // namespace mbgl
118