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