#include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace mbgl; TextBucket::TextBucket( TextVertexBuffer &vertexBuffer, TriangleElementsBuffer &triangleElementsBuffer, const StyleBucketText &properties, Placement &placement) : properties(properties), vertexBuffer(vertexBuffer), triangleElementsBuffer(triangleElementsBuffer), placement(placement), vertex_start(vertexBuffer.index()), triangle_elements_start(triangleElementsBuffer.index()) {} void TextBucket::addGlyphs(const PlacedGlyphs &glyphs, float placementZoom, PlacementRange placementRange, float zoom) { placementZoom += zoom; for (const PlacedGlyph &glyph : glyphs) { const auto &tl = glyph.tl; const auto &tr = glyph.tr; const auto &bl = glyph.bl; const auto &br = glyph.br; const auto &tex = glyph.tex; const auto &angle = glyph.angle; float minZoom = util::max( static_cast(zoom + log(glyph.glyphBox.minScale) / log(2)), placementZoom); float maxZoom = util::min( static_cast(zoom + log(glyph.glyphBox.maxScale) / log(2)), 25.0f); const auto &glyphAnchor = glyph.glyphBox.anchor; if (maxZoom <= minZoom) continue; // Lower min zoom so that while fading out the label // it can be shown outside of collision-free zoom levels if (minZoom == placementZoom) { minZoom = 0; } const int glyph_vertex_length = 4; if (!triangleGroups.size() || (triangleGroups.back().vertex_length + glyph_vertex_length > 65535)) { // Move to a new group because the old one can't hold the geometry. triangleGroups.emplace_back(); } // We're generating triangle fans, so we always start with the first // coordinate in this polygon. triangle_group_type &triangleGroup = triangleGroups.back(); uint32_t triangleIndex = triangleGroup.vertex_length; // coordinates (2 triangles) vertexBuffer.add(glyphAnchor.x, glyphAnchor.y, tl.x, tl.y, tex.x, tex.y, angle, minZoom, placementRange, maxZoom, placementZoom); vertexBuffer.add(glyphAnchor.x, glyphAnchor.y, tr.x, tr.y, tex.x + tex.w, tex.y, angle, minZoom, placementRange, maxZoom, placementZoom); vertexBuffer.add(glyphAnchor.x, glyphAnchor.y, bl.x, bl.y, tex.x, tex.y + tex.h, angle, minZoom, placementRange, maxZoom, placementZoom); vertexBuffer.add(glyphAnchor.x, glyphAnchor.y, br.x, br.y, tex.x + tex.w, tex.y + tex.h, angle, minZoom, placementRange, maxZoom, placementZoom); // add the two triangles, referencing the four coordinates we just // inserted. triangleElementsBuffer.add(triangleIndex + 0, triangleIndex + 1, triangleIndex + 2); triangleElementsBuffer.add(triangleIndex + 1, triangleIndex + 2, triangleIndex + 3); triangleGroup.vertex_length += glyph_vertex_length; triangleGroup.elements_length += 2; } }; void TextBucket::addFeature(const pbf &geom_pbf, const GlyphPositions &face, const Shaping &shaping) { // Decode all lines. std::vector line; Geometry::command cmd; Coordinate coord; pbf geom(geom_pbf); Geometry geometry(geom); int32_t x, y; while ((cmd = geometry.next(x, y)) != Geometry::end) { if (cmd == Geometry::move_to) { if (!line.empty()) { placement.addFeature(*this, line, properties, face, shaping); line.clear(); } } line.emplace_back(x, y); } if (line.size()) { placement.addFeature(*this, line, properties, face, shaping); } } void TextBucket::render(Painter &painter, std::shared_ptr layer_desc, const Tile::ID &id) { painter.renderText(*this, layer_desc, id); } bool TextBucket::hasData() const { return !triangleGroups.empty(); } void TextBucket::drawGlyphs(TextShader &shader) { char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); char *elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize); for (triangle_group_type &group : triangleGroups) { group.array.bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index); glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index); vertex_index += group.vertex_length * vertexBuffer.itemSize; elements_index += group.elements_length * triangleElementsBuffer.itemSize; } }