diff options
author | Ansis Brammanis <brammanis@gmail.com> | 2015-03-31 16:27:10 -0700 |
---|---|---|
committer | Ansis Brammanis <brammanis@gmail.com> | 2015-04-01 16:11:48 -0700 |
commit | 128ed1f26fa2688a10f3738222da033337c7b0e5 (patch) | |
tree | 689517e79a37ef370a11df672bdc251cb3e9bb5b /src | |
parent | 9309f59de3e156432087b55f0f7e3ebc026b78e8 (diff) | |
download | qtlocation-mapboxgl-128ed1f26fa2688a10f3738222da033337c7b0e5.tar.gz |
start porting symbol bucket changes
Diffstat (limited to 'src')
-rw-r--r-- | src/mbgl/renderer/symbol_bucket.cpp | 206 | ||||
-rw-r--r-- | src/mbgl/renderer/symbol_bucket.hpp | 35 | ||||
-rw-r--r-- | src/mbgl/text/glyph.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/text/shaping.hpp | 6 |
4 files changed, 106 insertions, 143 deletions
diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp index 166d5cf148..e684c3afd4 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -9,7 +9,6 @@ #include <mbgl/geometry/resample.hpp> #include <mbgl/renderer/painter.hpp> #include <mbgl/text/glyph_store.hpp> -#include <mbgl/text/shaping.hpp> #include <mbgl/text/quads.hpp> #include <mbgl/platform/log.hpp> #include <mbgl/text/collision.hpp> @@ -23,6 +22,20 @@ namespace mbgl { +SymbolInstance::SymbolInstance(Anchor &anchor, const std::vector<Coordinate> &line, + const Shaping &shapedText, const PositionedIcon &shapedIcon, + const StyleLayoutSymbol &layout, const bool inside, + const float textBoxScale, const float /*textPadding*/, const float textAlongLine, + const float /*iconBoxScale*/, const float /*iconPadding*/, const float iconAlongLine, + const GlyphPositions &face) : + hasText(shapedText), hasIcon(shapedIcon), + glyphQuads(inside && shapedText ? + getGlyphQuads(anchor, shapedText, textBoxScale, line, layout, textAlongLine, face) : + PlacedGlyphs()), + iconQuads(inside && shapedIcon ? + getIconQuads(anchor, shapedIcon, line, layout, iconAlongLine) : + PlacedGlyphs()) {}; + SymbolBucket::SymbolBucket(std::unique_ptr<const StyleLayoutSymbol> styleLayout_, Collision &collision_) : styleLayout(std::move(styleLayout_)), collision(collision_) { assert(styleLayout); @@ -170,22 +183,22 @@ void SymbolBucket::addFeatures(const GeometryTileLayer& layer, break; } - float justify = 0.5; - if (layout.text.justify == TextJustifyType::Right) justify = 1; - else if (layout.text.justify == TextJustifyType::Left) justify = 0; + const float justify = layout.text.justify == TextJustifyType::Right ? 1 : + layout.text.justify == TextJustifyType::Left ? 0 : + 0.5; const auto &fontStack = glyphStore.getFontStack(layout.text.font); for (const SymbolFeature &feature : features) { if (!feature.geometry.size()) continue; - Shaping shaping; - Rect<uint16_t> image; + Shaping shapedText; + PositionedIcon shapedIcon; GlyphPositions face; // if feature has text, shape the text if (feature.label.length()) { - shaping = fontStack->getShaping( + shapedText = fontStack->getShaping( /* string */ feature.label, /* maxWidth: ems */ layout.text.max_width * 24, /* lineHeight: ems */ layout.text.line_height * 24, @@ -196,7 +209,7 @@ void SymbolBucket::addFeatures(const GeometryTileLayer& layer, /* translate */ vec2<float>(layout.text.offset[0], layout.text.offset[1])); // Add the glyphs we need for this label to the glyph atlas. - if (shaping.positionedGlyphs.size()) { + if (shapedText) { glyphAtlas.addGlyphs(tileUID, feature.label, layout.text.font, fontStack, face); } } @@ -204,164 +217,101 @@ void SymbolBucket::addFeatures(const GeometryTileLayer& layer, // if feature has icon, get sprite atlas position if (feature.sprite.length()) { sprite.waitUntilLoaded(); - image = spriteAtlas.getImage(feature.sprite, false); + Rect<uint16_t> image = spriteAtlas.getImage(feature.sprite, false); + shapedIcon = shapeIcon(image, layout); if (sprite.getSpritePosition(feature.sprite).sdf) { sdfIcons = true; } } - // if either shaping or icon position is present, add the feature - if (shaping.positionedGlyphs.size() || image) { - for (const std::vector<Coordinate> &line : feature.geometry) { - if (line.size()) { - addFeature(line, shaping, face, image); - } - } + // if either shapedText or icon position is present, add the feature + if (shapedText || shapedIcon) { + addFeature(feature.geometry, shapedText, shapedIcon, face); } } + + placeFeatures(); } -bool byScale(const Anchor &a, const Anchor &b) { return a.scale < b.scale; } -void SymbolBucket::addFeature(const std::vector<Coordinate> &line, const Shaping &shaping, - const GlyphPositions &face, const Rect<uint16_t> &image) { - assert(line.size()); +void SymbolBucket::addFeature(const std::vector<std::vector<Coordinate>> &lines, + const Shaping &shapedText, const PositionedIcon &shapedIcon, const GlyphPositions &face) { auto &layout = *styleLayout; const float minScale = 0.5f; const float glyphSize = 24.0f; - const bool horizontalText = - layout.text.rotation_alignment == RotationAlignmentType::Viewport; - const bool horizontalIcon = - layout.icon.rotation_alignment == RotationAlignmentType::Viewport; const float fontScale = layout.text.max_size / glyphSize; const float textBoxScale = collision.tilePixelRatio * fontScale; - //const float iconBoxScale = collision.tilePixelRatio * layout.icon.max_size; - const bool iconWithoutText = layout.text.optional || !shaping.positionedGlyphs.size(); - const bool textWithoutIcon = layout.icon.optional || !image; + const float iconBoxScale = collision.tilePixelRatio * layout.icon.max_size; + //const float symbolSpacing = collision.tilePixelRatio * layout.min_distance; const bool avoidEdges = layout.avoid_edges && layout.placement != PlacementType::Line; + const float textPadding = layout.text.padding * collision.tilePixelRatio; + const float iconPadding = layout.icon.padding * collision.tilePixelRatio; + //const float textMaxAngle = layout.text.max_angle * M_PI / 180; + const bool textAlongLine = + layout.text.rotation_alignment != RotationAlignmentType::Viewport && + layout.placement == PlacementType::Line; + const bool iconAlongLine = + layout.icon.rotation_alignment != RotationAlignmentType::Viewport && + layout.placement == PlacementType::Line; - Anchors anchors; + // TODO clip lines here - if (layout.placement == PlacementType::Line) { - float resampleOffset = 0; - - if (shaping.positionedGlyphs.size()) { - float minX = std::numeric_limits<float>::infinity(); - float maxX = -std::numeric_limits<float>::infinity(); - for (const auto &glyph : shaping.positionedGlyphs) { - minX = std::min(minX, glyph.x); - maxX = std::max(maxX, glyph.x); - } - const float labelLength = maxX - minX; - resampleOffset = (labelLength / 2.0 + glyphSize * 2.0) * fontScale; - } + for (const std::vector<Coordinate> &line : lines) { + if (!line.size()) continue; - // Line labels - anchors = resample(line, layout.min_distance, minScale, collision.maxPlacementScale, - collision.tilePixelRatio, resampleOffset); + // Calculate the anchor points around which you want to place labels + Anchors anchors = layout.placement == PlacementType::Line ? + resample(line, layout.min_distance, minScale, collision.maxPlacementScale, collision.tilePixelRatio, 0.0f) : + Anchors({ Anchor(float(line[0].x), float(line[0].y), 0, minScale) }); - // Sort anchors by segment so that we can start placement with the - // anchors that can be shown at the lowest zoom levels. - std::sort(anchors.begin(), anchors.end(), byScale); - } else { - // Point labels - anchors = {Anchor{float(line[0].x), float(line[0].y), 0, minScale}}; - } + // For each potential label, create the placement features used to check for collisions, and the quads use for rendering. + for (Anchor &anchor : anchors) { - // TODO: figure out correct ascender height. - const vec2<float> origin = {0, -17}; + const bool inside = !(anchor.x < 0 || anchor.x > 4096 || anchor.y < 0 || anchor.y > 4096); - for (Anchor &anchor : anchors) { + if (avoidEdges && !inside) continue; - // Calculate the scales at which the text and icons can be first shown without overlap - PlacedGlyphs placedGlyphs; - PlacedGlyphs placedIcons; - float glyphScale = 0; - float iconScale = 0; - const bool inside = !(anchor.x < 0 || anchor.x > 4096 || anchor.y < 0 || anchor.y > 4096); + symbolInstances.emplace_back(anchor, line, shapedText, shapedIcon, layout, inside, + textBoxScale, textPadding, textAlongLine, + iconBoxScale, iconPadding, iconAlongLine, + face); + } + } +} - if (avoidEdges && !inside) continue; +void SymbolBucket::placeFeatures() { - if (shaping.positionedGlyphs.size()) { + //auto &layout = *styleLayout; - placedGlyphs = getGlyphQuads(anchor, shaping, textBoxScale, line, layout, !horizontalText, face); - glyphScale = 0.5f; - /* - layout.text.allow_overlap - ? glyphPlacement.minScale - : collision.getPlacementScale(glyphPlacement.boxes, glyphPlacement.minScale, avoidEdges); - */ - if (!glyphScale && !iconWithoutText) - continue; - } + for (SymbolInstance &symbolInstance : symbolInstances) { - if (image) { - auto shapedImage = shapeIcon(image, layout); - placedIcons = getIconQuads(anchor, shapedImage, line, layout, !horizontalIcon); - iconScale = 0.5f; - /* - layout.icon.allow_overlap - ? iconPlacement.minScale - : collision.getPlacementScale(iconPlacement.boxes, iconPlacement.minScale, avoidEdges); - */ - if (!iconScale && !textWithoutIcon) - continue; - } + const bool hasText = symbolInstance.hasText; + const bool hasIcon = symbolInstance.hasIcon; - if (!iconWithoutText && !textWithoutIcon) { - iconScale = glyphScale = util::max(iconScale, glyphScale); - } else if (!textWithoutIcon && glyphScale) { - glyphScale = util::max(iconScale, glyphScale); - } else if (!iconWithoutText && iconScale) { - iconScale = util::max(iconScale, glyphScale); - } + float glyphScale = 0.5f; + float iconScale = 0.5f; - // Get the rotation ranges it is safe to show the glyphs /* - PlacementRange glyphRange = fullRange; - (!glyphScale || layout.text.allow_overlap) - ? fullRange - : collision.getPlacementRange(glyphPlacement.boxes, glyphScale, horizontalText); - PlacementRange iconRange = - (!iconScale || layout.icon.allow_overlap) - ? fullRange - : collision.getPlacementRange(iconPlacement.boxes, iconScale, horizontalIcon); - - const PlacementRange maxRange = {{ - util::min(iconRange[0], glyphRange[0]), util::max(iconRange[1], glyphRange[1]), - }}; - - if (!iconWithoutText && !textWithoutIcon) { - iconRange = glyphRange = maxRange; - } else if (!textWithoutIcon) { - glyphRange = maxRange; - } else if (!iconWithoutText) { - iconRange = maxRange; - } - */ + if (!iconWithoutText && !textWithoutIcon) { + iconScale = glyphScale = util::max(iconScale, glyphScale); + } else if (!textWithoutIcon && glyphScale) { + glyphScale = util::max(iconScale, glyphScale); + } else if (!iconWithoutText && iconScale) { + iconScale = util::max(iconScale, glyphScale); + } + */ // Insert final placement into collision tree and add glyphs/icons to buffers - if (glyphScale && std::isfinite(glyphScale)) { - if (!layout.text.ignore_placement) { - /* - collision.insert(glyphPlacement.boxes, anchor, glyphScale, glyphRange, - horizontalText); - */ - } - if (inside) addSymbols<TextBuffer, TextElementGroup>(text, placedGlyphs, glyphScale); + if (hasText && std::isfinite(glyphScale)) { + addSymbols<TextBuffer, TextElementGroup>(text, symbolInstance.glyphQuads, glyphScale); } - if (iconScale && std::isfinite(iconScale)) { - /* - if (!layout.icon.ignore_placement) { - collision.insert(iconPlacement.boxes, anchor, iconScale, iconRange, horizontalIcon); - } - */ - if (inside) addSymbols<IconBuffer, IconElementGroup>(icon, placedIcons, iconScale); + if (hasIcon && std::isfinite(iconScale)) { + addSymbols<IconBuffer, IconElementGroup>(icon, symbolInstance.iconQuads, iconScale); } } } diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp index dd55d37219..d1abe0a2c0 100644 --- a/src/mbgl/renderer/symbol_bucket.hpp +++ b/src/mbgl/renderer/symbol_bucket.hpp @@ -9,6 +9,7 @@ #include <mbgl/geometry/icon_buffer.hpp> #include <mbgl/text/types.hpp> #include <mbgl/text/glyph.hpp> +#include <mbgl/text/shaping.hpp> #include <mbgl/style/style_bucket.hpp> #include <mbgl/util/ptr.hpp> @@ -37,20 +38,24 @@ public: std::string sprite; }; - -class Symbol { -public: - vec2<float> tl, tr, bl, br; - Rect<uint16_t> tex; - float angle; - float minScale = 0.0f; - float maxScale = std::numeric_limits<float>::infinity(); - CollisionAnchor anchor; +struct Anchor; + +class SymbolInstance { + public: + explicit SymbolInstance(Anchor &anchor, const std::vector<Coordinate> &line, + const Shaping &shapedText, const PositionedIcon &shapedIcon, + const StyleLayoutSymbol &layout, const bool inside, + const float textBoxScale, const float textPadding, const float textAlongLine, + const float iconBoxScale, const float iconPadding, const float iconAlongLine, + const GlyphPositions &face); + const bool hasText; + const bool hasIcon; + const PlacedGlyphs glyphQuads; + const PlacedGlyphs iconQuads; + // text collision feature + // icon collision feature }; -typedef std::vector<Symbol> Symbols; - - class SymbolBucket : public Bucket { typedef ElementGroup<1> TextElementGroup; typedef ElementGroup<2> IconElementGroup; @@ -82,8 +87,11 @@ private: const FilterExpression&, GlyphStore&, const Sprite&); + void addFeature(const std::vector<std::vector<Coordinate>> &lines, + const Shaping &shapedText, const PositionedIcon &shapedIcon, + const GlyphPositions &face); - void addFeature(const std::vector<Coordinate> &line, const Shaping &shaping, const GlyphPositions &face, const Rect<uint16_t> &image); + void placeFeatures(); // Adds placed items to the buffer. template <typename Buffer, typename GroupType> @@ -95,6 +103,7 @@ public: private: Collision &collision; + std::vector<SymbolInstance> symbolInstances; struct TextBuffer { TextVertexBuffer vertices; diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp index eee7572af9..254cc212ec 100644 --- a/src/mbgl/text/glyph.hpp +++ b/src/mbgl/text/glyph.hpp @@ -64,6 +64,8 @@ class Shaping { int32_t bottom; int32_t left; int32_t right; + + operator bool() const { return positionedGlyphs.size(); } }; } diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp index 0af75b44cb..6e55fabae6 100644 --- a/src/mbgl/text/shaping.hpp +++ b/src/mbgl/text/shaping.hpp @@ -11,14 +11,16 @@ namespace mbgl { class PositionedIcon { public: inline explicit PositionedIcon() {} - inline explicit PositionedIcon(const Rect<uint16_t> _image, + inline explicit PositionedIcon(Rect<uint16_t> _image, float _top, float _bottom, float _left, float _right) : image(_image), top(_top), bottom(_bottom), left(_left), right(_right) {} - const Rect<uint16_t> image; + Rect<uint16_t> image; float top = 0; float bottom = 0; float left = 0; float right = 0; + + operator bool() const { return image; } }; class StyleLayoutSymbol; |