summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mbgl/style/types.hpp3
-rw-r--r--src/mbgl/renderer/line_bucket.cpp67
-rw-r--r--src/mbgl/renderer/line_bucket.hpp3
3 files changed, 64 insertions, 9 deletions
diff --git a/include/mbgl/style/types.hpp b/include/mbgl/style/types.hpp
index f6ffcd6865..e46ece6f4a 100644
--- a/include/mbgl/style/types.hpp
+++ b/include/mbgl/style/types.hpp
@@ -92,6 +92,8 @@ enum class JoinType : uint8_t {
Miter,
Bevel,
Round,
+ // the following two types are for internal use only
+ FakeRound,
FlipBevel
};
@@ -99,6 +101,7 @@ MBGL_DEFINE_ENUM_CLASS(JoinTypeClass, JoinType, {
{ JoinType::Miter, "miter" },
{ JoinType::Bevel, "bevel" },
{ JoinType::Round, "round" },
+ { JoinType::FakeRound, "fakeround" },
{ JoinType::FlipBevel, "flipbevel" },
});
diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp
index 0ba91af34d..446c75de76 100644
--- a/src/mbgl/renderer/line_bucket.cpp
+++ b/src/mbgl/renderer/line_bucket.cpp
@@ -146,8 +146,12 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
const CapType currentCap = nextVertex ? beginCap : endCap;
if (middleVertex) {
- if (currentJoin == JoinType::Round && miterLength < layout.round_limit) {
- currentJoin = JoinType::Miter;
+ if (currentJoin == JoinType::Round) {
+ if (miterLength < layout.round_limit) {
+ currentJoin = JoinType::Miter;
+ } else if (miterLength <= 2) {
+ currentJoin = JoinType::FakeRound;
+ }
}
if (currentJoin == JoinType::Miter && miterLength > miterLimit) {
@@ -191,13 +195,13 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
triangleStore);
flip = -flip;
- } else if (middleVertex && currentJoin == JoinType::Bevel) {
- const float dir = prevNormal.x * nextNormal.y - prevNormal.y * nextNormal.x;
+ } else if (middleVertex && (currentJoin == JoinType::Bevel || currentJoin == JoinType::FakeRound)) {
+ const bool lineTurnsLeft = flip * (prevNormal.x * nextNormal.y - prevNormal.y * nextNormal.x) > 0;
const float offset = -std::sqrt(miterLength * miterLength - 1);
float offsetA;
float offsetB;
- if (flip * dir > 0) {
+ if (lineTurnsLeft) {
offsetB = 0;
offsetA = offset;
} else {
@@ -211,6 +215,29 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
startVertex, triangleStore);
}
+ if (currentJoin == JoinType::FakeRound) {
+ // The join angle is sharp enough that a round join would be visible.
+ // Bevel joins fill the gap between segments with a single pie slice triangle.
+ // Create a round join by adding multiple pie slices. The join isn't actually round, but
+ // it looks like it is at the sizes we render lines at.
+
+ // Add more triangles for sharper angles.
+ // This math is just a good enough approximation. It isn't "correct".
+ const int n = std::floor((0.5 - (cosHalfAngle - 0.5)) * 8);
+
+ for (int m = 0; m < n; m++) {
+ auto approxFractionalJoinNormal = util::unit(nextNormal * ((m + 1.0f) / (n + 1.0f)) + prevNormal);
+ addPieSliceVertex(currentVertex, flip, distance, approxFractionalJoinNormal, lineTurnsLeft, startVertex, triangleStore);
+ }
+
+ addPieSliceVertex(currentVertex, flip, distance, joinNormal, lineTurnsLeft, startVertex, triangleStore);
+
+ for (int k = n - 1; k >= 0; k--) {
+ auto approxFractionalJoinNormal = util::unit(prevNormal * ((k + 1.0f) / (n + 1.0f)) + nextNormal);
+ addPieSliceVertex(currentVertex, flip, distance, approxFractionalJoinNormal, lineTurnsLeft, startVertex, triangleStore);
+ }
+ }
+
// Start next segment
if (nextVertex) {
addCurrentVertex(currentVertex, flip, distance, nextNormal, -offsetA, -offsetB,
@@ -260,15 +287,14 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
// The segment is done. Unset vertices to disconnect segments.
e1 = e2 = -1;
flip = 1;
+ }
- } else if (beginCap == CapType::Round) {
+ // Start next segment with a butt
+ if (nextVertex) {
// Add round cap before first segment
addCurrentVertex(currentVertex, flip, distance, nextNormal, -1, -1, true,
startVertex, triangleStore);
- }
- // Start next segment with a butt
- if (nextVertex) {
addCurrentVertex(currentVertex, flip, distance, nextNormal, 0, 0, false,
startVertex, triangleStore);
}
@@ -337,6 +363,29 @@ void LineBucket::addCurrentVertex(const Coordinate& currentVertex,
e2 = e3;
}
+void LineBucket::addPieSliceVertex(const Coordinate& currentVertex,
+ float flip,
+ double distance,
+ const vec2<double>& extrude,
+ bool lineTurnsLeft,
+ int32_t startVertex,
+ std::vector<TriangleElement>& triangleStore) {
+ int8_t ty = lineTurnsLeft;
+
+ auto flippedExtrude = extrude * (flip * (lineTurnsLeft ? -1 : 1));
+ e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, flippedExtrude.x, flippedExtrude.y, 0, ty,
+ distance) - startVertex;
+ if (e1 >= 0 && e2 >= 0) {
+ triangleStore.emplace_back(e1, e2, e3);
+ }
+
+ if (lineTurnsLeft) {
+ e2 = e3;
+ } else {
+ e1 = e3;
+ }
+}
+
void LineBucket::upload() {
vertexBuffer.upload();
triangleElementsBuffer.upload();
diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/line_bucket.hpp
index 6f13e3c819..cd5fce3cb9 100644
--- a/src/mbgl/renderer/line_bucket.hpp
+++ b/src/mbgl/renderer/line_bucket.hpp
@@ -47,6 +47,9 @@ private:
void addCurrentVertex(const Coordinate& currentVertex, float flip, double distance,
const vec2<double>& normal, float endLeft, float endRight, bool round,
int32_t startVertex, std::vector<LineBucket::TriangleElement>& triangleStore);
+ void addPieSliceVertex(const Coordinate& currentVertex, float flip, double distance,
+ const vec2<double>& extrude, bool lineTurnsLeft, int32_t startVertex,
+ std::vector<TriangleElement>& triangleStore);
public:
StyleLayoutLine layout;