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