1 #include <mbgl/renderer/buckets/fill_bucket.hpp>
2 #include <mbgl/programs/fill_program.hpp>
3 #include <mbgl/renderer/bucket_parameters.hpp>
4 #include <mbgl/style/layers/fill_layer_impl.hpp>
5 #include <mbgl/renderer/layers/render_fill_layer.hpp>
6 #include <mbgl/util/math.hpp>
7
8 #include <mapbox/earcut.hpp>
9
10 #include <cassert>
11
12 namespace mapbox {
13 namespace util {
14 template <> struct nth<0, mbgl::GeometryCoordinate> {
getmapbox::util::nth15 static int64_t get(const mbgl::GeometryCoordinate& t) { return t.x; };
16 };
17
18 template <> struct nth<1, mbgl::GeometryCoordinate> {
getmapbox::util::nth19 static int64_t get(const mbgl::GeometryCoordinate& t) { return t.y; };
20 };
21 } // namespace util
22 } // namespace mapbox
23
24 namespace mbgl {
25
26 using namespace style;
27
28 struct GeometryTooLongException : std::exception {};
29
FillBucket(const BucketParameters & parameters,const std::vector<const RenderLayer * > & layers)30 FillBucket::FillBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers)
31 : Bucket(LayerType::Fill) {
32 for (const auto& layer : layers) {
33 paintPropertyBinders.emplace(
34 std::piecewise_construct,
35 std::forward_as_tuple(layer->getID()),
36 std::forward_as_tuple(
37 layer->as<RenderFillLayer>()->evaluated,
38 parameters.tileID.overscaledZ));
39 }
40 }
41
addFeature(const GeometryTileFeature & feature,const GeometryCollection & geometry)42 void FillBucket::addFeature(const GeometryTileFeature& feature,
43 const GeometryCollection& geometry) {
44 for (auto& polygon : classifyRings(geometry)) {
45 // Optimize polygons with many interior rings for earcut tesselation.
46 limitHoles(polygon, 500);
47
48 std::size_t totalVertices = 0;
49
50 for (const auto& ring : polygon) {
51 totalVertices += ring.size();
52 if (totalVertices > std::numeric_limits<uint16_t>::max())
53 throw GeometryTooLongException();
54 }
55
56 std::size_t startVertices = vertices.vertexSize();
57
58 for (const auto& ring : polygon) {
59 std::size_t nVertices = ring.size();
60
61 if (nVertices == 0)
62 continue;
63
64 if (lineSegments.empty() || lineSegments.back().vertexLength + nVertices > std::numeric_limits<uint16_t>::max()) {
65 lineSegments.emplace_back(vertices.vertexSize(), lines.indexSize());
66 }
67
68 auto& lineSegment = lineSegments.back();
69 assert(lineSegment.vertexLength <= std::numeric_limits<uint16_t>::max());
70 uint16_t lineIndex = lineSegment.vertexLength;
71
72 vertices.emplace_back(FillProgram::layoutVertex(ring[0]));
73 lines.emplace_back(lineIndex + nVertices - 1, lineIndex);
74
75 for (uint32_t i = 1; i < nVertices; i++) {
76 vertices.emplace_back(FillProgram::layoutVertex(ring[i]));
77 lines.emplace_back(lineIndex + i - 1, lineIndex + i);
78 }
79
80 lineSegment.vertexLength += nVertices;
81 lineSegment.indexLength += nVertices * 2;
82 }
83
84 std::vector<uint32_t> indices = mapbox::earcut(polygon);
85
86 std::size_t nIndicies = indices.size();
87 assert(nIndicies % 3 == 0);
88
89 if (triangleSegments.empty() || triangleSegments.back().vertexLength + totalVertices > std::numeric_limits<uint16_t>::max()) {
90 triangleSegments.emplace_back(startVertices, triangles.indexSize());
91 }
92
93 auto& triangleSegment = triangleSegments.back();
94 assert(triangleSegment.vertexLength <= std::numeric_limits<uint16_t>::max());
95 uint16_t triangleIndex = triangleSegment.vertexLength;
96
97 for (uint32_t i = 0; i < nIndicies; i += 3) {
98 triangles.emplace_back(triangleIndex + indices[i],
99 triangleIndex + indices[i + 1],
100 triangleIndex + indices[i + 2]);
101 }
102
103 triangleSegment.vertexLength += totalVertices;
104 triangleSegment.indexLength += nIndicies;
105 }
106
107 for (auto& pair : paintPropertyBinders) {
108 pair.second.populateVertexVectors(feature, vertices.vertexSize());
109 }
110 }
111
upload(gl::Context & context)112 void FillBucket::upload(gl::Context& context) {
113 vertexBuffer = context.createVertexBuffer(std::move(vertices));
114 lineIndexBuffer = context.createIndexBuffer(std::move(lines));
115 triangleIndexBuffer = context.createIndexBuffer(std::move(triangles));
116
117 for (auto& pair : paintPropertyBinders) {
118 pair.second.upload(context);
119 }
120
121 uploaded = true;
122 }
123
hasData() const124 bool FillBucket::hasData() const {
125 return !triangleSegments.empty() || !lineSegments.empty();
126 }
127
getQueryRadius(const RenderLayer & layer) const128 float FillBucket::getQueryRadius(const RenderLayer& layer) const {
129 if (!layer.is<RenderFillLayer>()) {
130 return 0;
131 }
132
133 const std::array<float, 2>& translate = layer.as<RenderFillLayer>()->evaluated.get<FillTranslate>();
134 return util::length(translate[0], translate[1]);
135
136 }
137
138 } // namespace mbgl
139