diff options
author | Ansis Brammanis <brammanis@gmail.com> | 2017-06-20 12:38:02 -0400 |
---|---|---|
committer | Ansis Brammanis <brammanis@gmail.com> | 2017-06-20 12:38:02 -0400 |
commit | a200c8be04e6ea13f14a7d74dce1a66d9eea1506 (patch) | |
tree | 08be8ee7084882fbb4e0b53a608f8a27e1837c87 | |
parent | 6f299f514d4f8db9cb9e5d145d1776cc5b3023fd (diff) |
progress
-rw-r--r-- | src/mbgl/layout/symbol_layout.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/layout/symbol_projection.cpp | 162 | ||||
-rw-r--r-- | src/mbgl/layout/symbol_projection.hpp | 3 | ||||
-rw-r--r-- | src/mbgl/renderer/buckets/symbol_bucket.hpp | 20 | ||||
-rw-r--r-- | src/mbgl/renderer/layers/render_symbol_layer.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/layers/render_symbol_layer.hpp | 1 | ||||
-rw-r--r-- | src/mbgl/renderer/painters/painter_symbol.cpp | 11 |
7 files changed, 195 insertions, 8 deletions
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index b0430de92..c59f1040a 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -505,6 +505,8 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile) bucket->text, *bucket->textSizeBinder, symbol, feature, placementZoom, keepUpright, textPlacement, collisionTile.config.angle, symbolInstance.writingModes, symbolInstance.point); } + PlacedSymbol placedSymbol(symbolInstance.point, 0, 0, 0, 0, 0, placementZoom, false); + bucket->text.placedSymbols.emplace_back(std::move(placedSymbol)); } } @@ -515,6 +517,8 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile) addSymbol( bucket->icon, *bucket->iconSizeBinder, *symbolInstance.iconQuad, feature, placementZoom, keepUpright, iconPlacement, collisionTile.config.angle, symbolInstance.writingModes, symbolInstance.point); + PlacedSymbol placedSymbol(symbolInstance.point, 0, 0, 0, 0, 0, placementZoom, false); + bucket->icon.placedSymbols.emplace_back(std::move(placedSymbol)); } } diff --git a/src/mbgl/layout/symbol_projection.cpp b/src/mbgl/layout/symbol_projection.cpp index 6efe218ba..b740688e3 100644 --- a/src/mbgl/layout/symbol_projection.cpp +++ b/src/mbgl/layout/symbol_projection.cpp @@ -1,9 +1,10 @@ #include <mbgl/layout/symbol_projection.hpp> - #include <mbgl/map/transform_state.hpp> #include <mbgl/renderer/render_tile.hpp> #include <mbgl/renderer/buckets/symbol_bucket.hpp> #include <mbgl/renderer/layers/render_symbol_layer.hpp> +#include <mbgl/util/optional.hpp> +#include <mbgl/util/math.hpp> namespace mbgl { @@ -40,11 +41,164 @@ namespace mbgl { return m; } - void reprojectLineLabels(SymbolBucket& bucket, const mat4& posMatrix, const bool isText, const style::SymbolPropertyValues& values, const RenderTile& tile) { + + Point<float> project(const Point<float>& point, const mat4& matrix) { + vec4 pos = {{ point.x, point.y, 0, 1 }}; + matrix::transformMat4(pos, pos, matrix); + return { static_cast<float>(pos[0] / pos[3]), static_cast<float>(pos[1] / pos[3]) }; + } + + bool isVisible(const vec4& anchorPos, const float, const std::array<double, 2>& clippingBuffer) { + const float x = anchorPos[0] / anchorPos[3]; + const float y = anchorPos[1] / anchorPos[3]; + const bool inPaddedViewport = ( + x >= -clippingBuffer[0] && + x <= clippingBuffer[0] && + y >= -clippingBuffer[1] && + y <= clippingBuffer[1]); + // TODO do framehistory check here as well + return inPaddedViewport; + } + + void addDynamicAttributes(const Point<float>&, const float, const float) { + } + + void hideGlyphs(size_t) { + } + + struct PlacedGlyph { + PlacedGlyph(Point<float> point_, float angle_) : point(point_), angle(angle_) {} + Point<float> point; + float angle; + }; + + optional<PlacedGlyph> placeGlyphAlongLine(const float offsetX, const float lineOffsetX, const float lineOffsetY, const bool flip, + Point<float> anchorPoint, const uint16_t anchorSegment, const std::vector<Point<float>>& line, const mat4& labelPlaneMatrix) { + + const float combinedOffsetX = flip ? + offsetX - lineOffsetX : + offsetX + lineOffsetX; + + int16_t dir = combinedOffsetX > 0 ? 1 : -1; + + float angle = 0.0; + if (flip) { + // The label needs to be flipped to keep text upright. + // Iterate in the reverse direction. + dir *= -1; + angle = M_PI; + } + + if (dir < 0) angle += M_PI; + + int32_t currentIndex = dir > 0 ? anchorSegment : anchorSegment + 1; + + Point<float>& current = anchorPoint; + Point<float>& prev = anchorPoint; + float distanceToPrev = 0.0; + float currentSegmentDistance = 0.0; + const float absOffsetX = std::abs(combinedOffsetX); + + while (distanceToPrev + currentSegmentDistance <= absOffsetX) { + currentIndex += dir; + + // offset does not fit on the projected line + if (currentIndex < 0 || currentIndex >= static_cast<int32_t>(line.size())) return {}; + + prev = current; + current = project(line.at(currentIndex), labelPlaneMatrix); + + distanceToPrev += currentSegmentDistance; + currentSegmentDistance = util::dist<float>(prev, current); + } + + // The point is on the current segment. Interpolate to find it. + const float segmentInterpolationT = (absOffsetX - distanceToPrev) / currentSegmentDistance; + const Point<float> prevToCurrent = current - prev; + Point<float> p = (prevToCurrent * segmentInterpolationT) + prev; + + // offset the point from the line to text-offset and icon-offset + p += util::perp(prevToCurrent) * static_cast<float>(lineOffsetY * dir / util::mag(prevToCurrent)); + + const float segmentAngle = angle + std::atan2(current.y - prev.y, current.x - prev.x); + + return {{ p, segmentAngle }}; + } + + void placeGlyphsAlongLine(const PlacedSymbol& symbol, const float fontSize, const bool flip, const mat4& labelPlaneMatrix) { + const float fontScale = fontSize / 24.0; + const float lineOffsetX = symbol.lineOffsetX * fontSize; + const float lineOffsetY = symbol.lineOffsetY * fontSize; + + const Point<float> anchorPoint = project(symbol.anchorPoint, labelPlaneMatrix); + + std::vector<PlacedGlyph> placedGlyphs; + for (auto glyphOffsetX : symbol.glyphOffsets) { + auto placedGlyph = placeGlyphAlongLine(glyphOffsetX * fontScale, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix); + if (placedGlyph) { + placedGlyphs.push_back(*placedGlyph); + } else { + hideGlyphs(symbol.glyphOffsets.size()); + return; + } + } + + for (auto& placedGlyph : placedGlyphs) { + addDynamicAttributes(placedGlyph.point, placedGlyph.angle, symbol.placementZoom); + } + } + + void reprojectLineLabels(SymbolBucket& bucket, const mat4& posMatrix, const bool isText, const style::SymbolPropertyValues& values, + //const RenderTile& tile, const TransformState& state) { + const RenderTile&, const TransformState& state) { // const sizeData = isText ? bucket.textSizeData : bucket.iconSizeData; // const partiallyEvaluatedSize = symbolSize.evaluateSizeForZoom(sizeData, painter.transform, layer, isText); - const std::array<float, 2> clippingBuffer(256.0 / state.getSize().width * 2.0 + 1.0, 256.0 / state.getHeight()); - const clippingBuffer = [256 / painter.width * 2 + 1, 256 / painter.height * 2 + 1]; + const std::array<double, 2> clippingBuffer = {{ 256.0 / state.getSize().width * 2.0 + 1.0, 256.0 / state.getSize().height }}; + + //TODO + const float pixelsToTileUnits = 1.0; + const mat4 labelPlaneMatrix = getLabelPlaneMatrix(posMatrix, values.pitchAlignment == style::AlignmentType::Map, + values.rotationAlignment == style::AlignmentType::Map, state, pixelsToTileUnits); + + // + // const dynamicLayoutVertexArray = isText ? + // bucket.buffers.glyph.dynamicLayoutVertexArray : + // bucket.buffers.icon.dynamicLayoutVertexArray; + // dynamicLayoutVertexArray.clear(); + + const std::vector<PlacedSymbol>& placedSymbols = isText ? bucket.text.placedSymbols : bucket.icon.placedSymbols; + for (auto& placedSymbol : placedSymbols) { + vec4 anchorPos = {{ placedSymbol.anchorPoint.x, placedSymbol.anchorPoint.y, 0, 1 }}; + matrix::transformMat4(anchorPos, anchorPos, posMatrix); + + // Don't bother calculating the correct point for invisible labels. + if (!isVisible(anchorPos, placedSymbol.placementZoom, clippingBuffer)) { + hideGlyphs(placedSymbol.glyphOffsets.size()); + continue; + } + + bool flip = false; + if (values.keepUpright) { + if (false) { + const Point<float> a = project(placedSymbol.line.at(placedSymbol.segment), posMatrix); + const Point<float> b = project(placedSymbol.line.at(placedSymbol.segment + 1), posMatrix); + flip = placedSymbol.vertical ? b.y > a.y : b.x < a.x; + } + } + + const float cameraToAnchorDistance = anchorPos[3]; + const float perspectiveRatio = 1 + 0.5 * ((cameraToAnchorDistance / state.getCameraToCenterDistance()) - 1.0); + + + //const fontSize = symbolSize.evaluateSizeForFeature(sizeData, partiallyEvaluatedSize, symbol); + const float fontSize = 16; + const float pitchScaledFontSize = values.pitchAlignment == style::AlignmentType::Map ? + fontSize * perspectiveRatio : + fontSize / perspectiveRatio; + + //placeGlyphsAlongLine(symbol, pitchScaledFontSize, flip, labelPlaneMatrix, bucket.glyphOffsetArray, lineVertexArray, dynamicLayoutVertexArray); + placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, flip, labelPlaneMatrix); + } } } // end namespace mbgl diff --git a/src/mbgl/layout/symbol_projection.hpp b/src/mbgl/layout/symbol_projection.hpp index e26b1f4e2..21bd1c78a 100644 --- a/src/mbgl/layout/symbol_projection.hpp +++ b/src/mbgl/layout/symbol_projection.hpp @@ -14,6 +14,7 @@ namespace mbgl { mat4 getLabelPlaneMatrix(const mat4& posMatrix, const bool pitchWithMap, const bool rotateWithMap, const TransformState& state, const float pixelsToTileUnits); mat4 getGlCoordMatrix(const mat4& posMatrix, const bool pitchWithMap, const bool rotateWithMap, const TransformState& state, const float pixelsToTileUnits); - void reprojectLineLabels(SymbolBucket& bucket, const mat4& posMatrix, const bool isText, const style::SymbolPropertyValues& values, const RenderTile& tile); + void reprojectLineLabels(SymbolBucket&, const mat4& posMatrix, const bool isText, const style::SymbolPropertyValues&, + const RenderTile&, const TransformState&); } // end namespace mbgl diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index 6a9382c3f..1534dbcf8 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -15,6 +15,24 @@ namespace mbgl { +class PlacedSymbol { +public: + PlacedSymbol(Point<float> anchorPoint_, uint16_t segment_, float lowerSize_, float upperSize_, + float lineOffsetX_, float lineOffsetY_, float placementZoom_, bool vertical_) : + anchorPoint(anchorPoint_), segment(segment_), lowerSize(lowerSize_), upperSize(upperSize_), + lineOffsetX(lineOffsetX_), lineOffsetY(lineOffsetY_), placementZoom(placementZoom_), vertical(vertical_) {} + Point<float> anchorPoint; + uint16_t segment; + float lowerSize; + float upperSize; + float lineOffsetX; + float lineOffsetY; + float placementZoom; + bool vertical; + std::vector<float> glyphOffsets; + std::vector<Point<float>> line; +}; + class SymbolBucket : public Bucket { public: SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated, @@ -47,6 +65,7 @@ public: gl::VertexVector<SymbolDynamicLayoutAttributes::Vertex> dynamicVertices; gl::IndexVector<gl::Triangles> triangles; gl::SegmentVector<SymbolTextAttributes> segments; + std::vector<PlacedSymbol> placedSymbols; optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer; optional<gl::VertexBuffer<SymbolDynamicLayoutAttributes::Vertex>> dynamicVertexBuffer; @@ -60,6 +79,7 @@ public: gl::VertexVector<SymbolDynamicLayoutAttributes::Vertex> dynamicVertices; gl::IndexVector<gl::Triangles> triangles; gl::SegmentVector<SymbolIconAttributes> segments; + std::vector<PlacedSymbol> placedSymbols; PremultipliedImage atlasImage; optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index a2c253bf4..67649f443 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -83,6 +83,7 @@ style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::S return style::SymbolPropertyValues { layout_.get<style::IconRotationAlignment>(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment layout_.get<style::IconRotationAlignment>(), + layout_.get<style::IconKeepUpright>(), evaluated.get<style::IconTranslate>(), evaluated.get<style::IconTranslateAnchor>(), evaluated.get<style::IconHaloColor>().constantOr(Color::black()).a > 0 && @@ -108,6 +109,7 @@ style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::S return style::SymbolPropertyValues { layout_.get<style::TextPitchAlignment>(), layout_.get<style::TextRotationAlignment>(), + layout_.get<style::TextKeepUpright>(), evaluated.get<style::TextTranslate>(), evaluated.get<style::TextTranslateAnchor>(), evaluated.get<style::TextHaloColor>().constantOr(Color::black()).a > 0 && diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp index 6f9f058a9..efdf5ba44 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.hpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp @@ -40,6 +40,7 @@ public: // Layout AlignmentType pitchAlignment; AlignmentType rotationAlignment; + bool keepUpright; // Paint std::array<float, 2> translate; diff --git a/src/mbgl/renderer/painters/painter_symbol.cpp b/src/mbgl/renderer/painters/painter_symbol.cpp index b52ce3a8d..04ca195ff 100644 --- a/src/mbgl/renderer/painters/painter_symbol.cpp +++ b/src/mbgl/renderer/painters/painter_symbol.cpp @@ -10,6 +10,7 @@ #include <mbgl/programs/collision_box_program.hpp> #include <mbgl/util/math.hpp> #include <mbgl/tile/geometry_tile.hpp> +#include <mbgl/layout/symbol_projection.hpp> #include <cmath> @@ -65,15 +66,16 @@ void Painter::renderSymbol(PaintParameters& parameters, assert(dynamic_cast<GeometryTile*>(&tile.tile)); GeometryTile& geometryTile = static_cast<GeometryTile&>(tile.tile); - const alongLine = bucket.layout.get<SymbolPlacement>() == SymbolPlacementType::Line && - bucket.layout.get<RotationAlignment>() == AlignmentType::Map; if (bucket.hasIconData()) { auto values = layer.iconPropertyValues(layout); auto paintPropertyValues = layer.iconPaintProperties(); + const bool alongLine = bucket.layout.get<SymbolPlacement>() == SymbolPlacementType::Line && + bucket.layout.get<IconRotationAlignment>() == AlignmentType::Map; + if (alongLine) { - reprojectLineLabels(bucket, tile.matrix, false, values, tile); + reprojectLineLabels(bucket, tile.matrix, false, values, tile, state); } const bool iconScaled = layout.get<IconSize>().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear; @@ -122,6 +124,9 @@ void Painter::renderSymbol(PaintParameters& parameters, auto values = layer.textPropertyValues(layout); auto paintPropertyValues = layer.textPaintProperties(); + const bool alongLine = bucket.layout.get<SymbolPlacement>() == SymbolPlacementType::Line && + bucket.layout.get<TextRotationAlignment>() == AlignmentType::Map; + const Size texsize = geometryTile.glyphAtlasTexture->size; if (values.hasHalo) { |