summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2015-04-27 12:22:24 +0200
committerKonstantin Käfer <mail@kkaefer.com>2015-04-27 12:22:24 +0200
commit99ab9c3c6debdf492aff7a751d82400eba1b1cdf (patch)
tree568e06c10643f5554a3cd00418a3d44f51bf5855
parent8aa2e2fef76eb4dfdb6e5b28a815babd27647322 (diff)
parentfeade7b4e42bf8d293d5023dc12ea2f9106e3b7c (diff)
downloadqtlocation-mapboxgl-99ab9c3c6debdf492aff7a751d82400eba1b1cdf.tar.gz
Merge pull request #1343 from mapbox/get-rid-of-gl-points
match -js line tesselation (get rid of joins drawn with GL_POINTS).
-rw-r--r--include/mbgl/util/math.hpp10
-rw-r--r--include/mbgl/util/vec.hpp8
-rw-r--r--src/mbgl/geometry/elements_buffer.cpp5
-rw-r--r--src/mbgl/geometry/elements_buffer.hpp10
-rw-r--r--src/mbgl/map/tile_parser.cpp3
-rw-r--r--src/mbgl/map/vector_tile_data.hpp1
-rw-r--r--src/mbgl/renderer/line_bucket.cpp506
-rw-r--r--src/mbgl/renderer/line_bucket.hpp29
-rw-r--r--src/mbgl/renderer/painter.cpp3
-rw-r--r--src/mbgl/renderer/painter.hpp2
-rw-r--r--src/mbgl/renderer/painter_line.cpp23
-rw-r--r--src/mbgl/shader/linejoin.fragment.glsl14
-rw-r--r--src/mbgl/shader/linejoin.vertex.glsl13
-rw-r--r--src/mbgl/shader/linejoin_shader.cpp22
-rw-r--r--src/mbgl/shader/linejoin_shader.hpp27
-rw-r--r--src/mbgl/style/types.hpp4
16 files changed, 285 insertions, 395 deletions
diff --git a/include/mbgl/util/math.hpp b/include/mbgl/util/math.hpp
index 647fa5e67f..6dea628e93 100644
--- a/include/mbgl/util/math.hpp
+++ b/include/mbgl/util/math.hpp
@@ -74,6 +74,11 @@ inline vec2<T> normal(const S1& a, const S2& b) {
return { dx / c, dy / c };
}
+template <typename T>
+inline T perp(const T& a) {
+ return T(-a.y, a.x);
+}
+
template <typename T, typename S1, typename S2>
inline T dist(const S1& a, const S2& b) {
T dx = b.x - a.x;
@@ -93,6 +98,11 @@ inline T mag(const S& a) {
return std::sqrt(a.x * a.x + a.y * a.y);
}
+template <typename S>
+inline S unit(const S& a) {
+ return a * (1 / mag(a));
+}
+
template <typename T>
T clamp(T value, T min, T max) {
return value < min ? min : (value > max ? max : value);
diff --git a/include/mbgl/util/vec.hpp b/include/mbgl/util/vec.hpp
index 32de852758..052dffcfa1 100644
--- a/include/mbgl/util/vec.hpp
+++ b/include/mbgl/util/vec.hpp
@@ -61,7 +61,13 @@ struct vec2 {
template <typename O>
inline typename std::enable_if<!std::is_arithmetic<O>::value, vec2>::type
operator-(const O &o) const {
- return {x - o.x, y - o.y};
+ return vec2<T>(x - o.x, y - o.y);
+ }
+
+ template <typename O>
+ inline typename std::enable_if<!std::is_arithmetic<O>::value, vec2>::type
+ operator+(const O &o) const {
+ return vec2<T>(x + o.x, y + o.y);
}
template <typename M>
diff --git a/src/mbgl/geometry/elements_buffer.cpp b/src/mbgl/geometry/elements_buffer.cpp
index 79af1b7e35..3e2e2794dd 100644
--- a/src/mbgl/geometry/elements_buffer.cpp
+++ b/src/mbgl/geometry/elements_buffer.cpp
@@ -14,8 +14,3 @@ void LineElementsBuffer::add(element_type a, element_type b) {
elements[0] = a;
elements[1] = b;
}
-
-void PointElementsBuffer::add(element_type a) {
- uint16_t *data = static_cast<element_type *>(addElement());
- data[0] = a;
-}
diff --git a/src/mbgl/geometry/elements_buffer.hpp b/src/mbgl/geometry/elements_buffer.hpp
index 5c1b421d35..24753ebafe 100644
--- a/src/mbgl/geometry/elements_buffer.hpp
+++ b/src/mbgl/geometry/elements_buffer.hpp
@@ -44,16 +44,6 @@ public:
void add(element_type a, element_type b);
};
-class PointElementsBuffer : public Buffer<
- 2, // bytes per point (1 unsigned short)
- GL_ELEMENT_ARRAY_BUFFER
-> {
-public:
- typedef uint16_t element_type;
-
- void add(element_type a);
-};
-
}
#endif
diff --git a/src/mbgl/map/tile_parser.cpp b/src/mbgl/map/tile_parser.cpp
index 275b77be91..d0d17aaf3d 100644
--- a/src/mbgl/map/tile_parser.cpp
+++ b/src/mbgl/map/tile_parser.cpp
@@ -172,8 +172,7 @@ std::unique_ptr<Bucket> TileParser::createFillBucket(const GeometryTileLayer& la
std::unique_ptr<Bucket> TileParser::createLineBucket(const GeometryTileLayer& layer,
const StyleBucket& bucket_desc) {
auto bucket = util::make_unique<LineBucket>(tile.lineVertexBuffer,
- tile.triangleElementsBuffer,
- tile.pointElementsBuffer);
+ tile.triangleElementsBuffer);
const float z = tile.id.z;
auto& layout = bucket->layout;
diff --git a/src/mbgl/map/vector_tile_data.hpp b/src/mbgl/map/vector_tile_data.hpp
index 4e2f252f85..e87978c24c 100644
--- a/src/mbgl/map/vector_tile_data.hpp
+++ b/src/mbgl/map/vector_tile_data.hpp
@@ -50,7 +50,6 @@ protected:
TriangleElementsBuffer triangleElementsBuffer;
LineElementsBuffer lineElementsBuffer;
- PointElementsBuffer pointElementsBuffer;
// Holds the buckets of this tile.
// They contain the location offsets in the buffers stored above
diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp
index 4e09b74640..78da158f1b 100644
--- a/src/mbgl/renderer/line_bucket.cpp
+++ b/src/mbgl/renderer/line_bucket.cpp
@@ -8,34 +8,25 @@
#include <mbgl/util/std.hpp>
#include <mbgl/platform/gl.hpp>
-#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
+#ifndef BUFFER_OFFSET
+#define BUFFER_OFFSET(i) ((char*)nullptr + (i))
+#endif
#include <cassert>
using namespace mbgl;
-LineBucket::LineBucket(LineVertexBuffer &vertexBuffer_,
- TriangleElementsBuffer &triangleElementsBuffer_,
- PointElementsBuffer &pointElementsBuffer_)
+LineBucket::LineBucket(LineVertexBuffer& vertexBuffer_,
+ TriangleElementsBuffer& triangleElementsBuffer_)
: vertexBuffer(vertexBuffer_),
triangleElementsBuffer(triangleElementsBuffer_),
- pointElementsBuffer(pointElementsBuffer_),
vertex_start(vertexBuffer_.index()),
- triangle_elements_start(triangleElementsBuffer_.index()),
- point_elements_start(pointElementsBuffer_.index()) {
-}
+ triangle_elements_start(triangleElementsBuffer_.index()){};
LineBucket::~LineBucket() {
// Do not remove. header file only contains forward definitions to unique pointers.
}
-struct TriangleElement {
- TriangleElement(uint16_t a_, uint16_t b_, uint16_t c_) : a(a_), b(b_), c(c_) {}
- uint16_t a, b, c;
-};
-
-typedef uint16_t PointElement;
-
void LineBucket::addGeometry(const GeometryCollection& geometryCollection) {
for (auto& line : geometryCollection) {
addGeometry(line);
@@ -43,366 +34,365 @@ void LineBucket::addGeometry(const GeometryCollection& geometryCollection) {
}
void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
- // TODO: use roundLimit
- // const float roundLimit = geometry.round_limit;
+ const auto len = [&vertices] {
+ auto l = vertices.size();
+ // If the line has duplicate vertices at the end, adjust length to remove them.
+ while (l > 2 && vertices[l - 1] == vertices[l - 2]) {
+ l--;
+ }
+ return l;
+ }();
- if (vertices.size() < 2) {
+ if (len < 2) {
// fprintf(stderr, "a line must have at least two vertices\n");
return;
}
- Coordinate firstVertex = vertices.front();
- Coordinate lastVertex = vertices.back();
- bool closed = firstVertex.x == lastVertex.x && firstVertex.y == lastVertex.y;
+ const float miterLimit = layout.join == JoinType::Bevel ? 1.05f : layout.miter_limit;
+
+ const Coordinate firstVertex = vertices.front();
+ const Coordinate lastVertex = vertices[len - 1];
+ const bool closed = firstVertex == lastVertex;
- if (vertices.size() == 2 && closed) {
+ if (len == 2 && closed) {
// fprintf(stderr, "a line may not have coincident points\n");
return;
}
- CapType beginCap = layout.cap;
- CapType endCap = closed ? CapType::Butt : layout.cap;
-
- JoinType currentJoin = JoinType::Miter;
-
- Coordinate currentVertex = Coordinate::null(),
- prevVertex = Coordinate::null(),
- nextVertex = Coordinate::null();
- vec2<double> prevNormal = vec2<double>::null(),
- nextNormal = vec2<double>::null();
-
- int32_t e1 = -1, e2 = -1, e3 = -1;
+ const CapType beginCap = layout.cap;
+ const CapType endCap = closed ? CapType::Butt : layout.cap;
int8_t flip = 1;
double distance = 0;
+ bool startOfLine = true;
+ Coordinate currentVertex = Coordinate::null(), prevVertex = Coordinate::null(),
+ nextVertex = Coordinate::null();
+ vec2<double> prevNormal = vec2<double>::null(), nextNormal = vec2<double>::null();
+
+ // the last three vertices added
+ e1 = e2 = e3 = -1;
if (closed) {
- currentVertex = vertices[vertices.size() - 2];
- nextNormal = util::normal<double>(currentVertex, lastVertex);
+ currentVertex = vertices[len - 2];
+ nextNormal = util::perp(util::unit(vec2<double>(firstVertex - currentVertex)));
}
- int32_t start_vertex = (int32_t)vertexBuffer.index();
-
- std::vector<TriangleElement> triangle_store;
- std::vector<PointElement> point_store;
+ const int32_t startVertex = (int32_t)vertexBuffer.index();
+ std::vector<TriangleElement> triangleStore;
- for (size_t i = 0; i < vertices.size(); ++i) {
- if (nextNormal) prevNormal = { -nextNormal.x, -nextNormal.y };
- if (currentVertex) prevVertex = currentVertex;
-
- currentVertex = vertices[i];
- currentJoin = layout.join;
-
- if (prevVertex) distance += util::dist<double>(currentVertex, prevVertex);
-
- // Find the next vertex.
- if (i + 1 < vertices.size()) {
+ for (size_t i = 0; i < len; ++i) {
+ if (closed && i == len - 1) {
+ // if the line is closed, we treat the last vertex like the first
+ nextVertex = vertices[i];
+ } else if (i + 1 < len) {
+ // just the next vertex
nextVertex = vertices[i + 1];
} else {
+ // there is no next vertex
nextVertex = Coordinate::null();
}
- // If the line is closed, we treat the last vertex like the first vertex.
- if (!nextVertex && closed) {
- nextVertex = vertices[1];
+ // if two consecutive vertices exist, skip the current one
+ if (nextVertex && vertices[i] == nextVertex) {
+ continue;
}
- if (nextVertex) {
- // if two consecutive vertices exist, skip one
- if (currentVertex.x == nextVertex.x && currentVertex.y == nextVertex.y) continue;
+ if (nextNormal) {
+ prevNormal = nextNormal;
+ }
+ if (currentVertex) {
+ prevVertex = currentVertex;
}
+ currentVertex = vertices[i];
+
+ // Calculate how far along the line the currentVertex is
+ if (prevVertex)
+ distance += util::dist<double>(currentVertex, prevVertex);
+
// Calculate the normal towards the next vertex in this line. In case
// there is no next vertex, pretend that the line is continuing straight,
- // meaning that we are just reversing the previous normal
- if (nextVertex) {
- nextNormal = util::normal<double>(currentVertex, nextVertex);
- } else {
- nextNormal = { -prevNormal.x, -prevNormal.y };
- }
+ // meaning that we are just using the previous normal.
+ nextNormal = nextVertex ? util::perp(util::unit(vec2<double>(nextVertex - currentVertex)))
+ : prevNormal;
// If we still don't have a previous normal, this is the beginning of a
// non-closed line, so we're doing a straight "join".
if (!prevNormal) {
- prevNormal = { -nextNormal.x, -nextNormal.y };
+ prevNormal = nextNormal;
}
// Determine the normal of the join extrusion. It is the angle bisector
// of the segments between the previous line and the next line.
- vec2<double> joinNormal = {
- prevNormal.x + nextNormal.x,
- prevNormal.y + nextNormal.y
- };
-
- // Cross product yields 0..1 depending on whether they are parallel
- // or perpendicular.
- double joinAngularity = nextNormal.x * joinNormal.y - nextNormal.y * joinNormal.x;
- joinNormal.x /= joinAngularity;
- joinNormal.y /= joinAngularity;
- double roundness = std::fmax(std::abs(joinNormal.x), std::abs(joinNormal.y));
-
-
- // Switch to miter joins if the angle is very low.
- if (currentJoin != JoinType::Miter) {
- if (std::fabs(joinAngularity) < 0.5 && roundness < layout.miter_limit) {
+ vec2<double> joinNormal = util::unit(prevNormal + nextNormal);
+
+ /* joinNormal prevNormal
+ * ↖ ↑
+ * .________. prevVertex
+ * |
+ * nextNormal ← | currentVertex
+ * |
+ * nextVertex !
+ *
+ */
+
+ // Calculate the length of the miter (the ratio of the miter to the width).
+ // Find the cosine of the angle between the next and join normals
+ // using dot product. The inverse of that is the miter length.
+ const float cosHalfAngle = joinNormal.x * nextNormal.x + joinNormal.y * nextNormal.y;
+ const float miterLength = 1 / cosHalfAngle;
+
+ // The join if a middle vertex, otherwise the cap
+ const bool middleVertex = prevVertex && nextVertex;
+ JoinType currentJoin = layout.join;
+ const CapType currentCap = nextVertex ? beginCap : endCap;
+
+ if (middleVertex) {
+ if (currentJoin == JoinType::Round && miterLength < layout.round_limit) {
currentJoin = JoinType::Miter;
}
- }
-
- // Add offset square begin cap.
- if (!prevVertex && beginCap == CapType::Square) {
- // Add first vertex
- e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
- flip * (prevNormal.x + prevNormal.y), flip * (-prevNormal.x + prevNormal.y), // extrude normal
- 0, 0, distance) - start_vertex; // texture normal
-
- if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
- e1 = e2; e2 = e3;
-
- // Add second vertex
- e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
- flip * (prevNormal.x - prevNormal.y), flip * (prevNormal.x + prevNormal.y), // extrude normal
- 0, 1, distance) - start_vertex; // texture normal
- if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
- e1 = e2; e2 = e3;
- }
-
- // Add offset square end cap.
- else if (!nextVertex && endCap == CapType::Square) {
- // Add first vertex
- e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
- nextNormal.x - flip * nextNormal.y, flip * nextNormal.x + nextNormal.y, // extrude normal
- 0, 0, distance) - start_vertex; // texture normal
-
- if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
- e1 = e2; e2 = e3;
+ if (currentJoin == JoinType::Miter && miterLength > miterLimit) {
+ currentJoin = JoinType::Bevel;
+ }
- // Add second vertex
- e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
- nextNormal.x + flip * nextNormal.y, -flip * nextNormal.x + nextNormal.y, // extrude normal
- 0, 1, distance) - start_vertex; // texture normal
+ if (currentJoin == JoinType::Bevel) {
+ // The maximum extrude length is 128 / 63 = 2 times the width of the line
+ // so if miterLength >= 2 we need to draw a different type of bevel where.
+ if (miterLength > 2) {
+ currentJoin = JoinType::FlipBevel;
+ }
- if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
- e1 = e2; e2 = e3;
+ // If the miterLength is really small and the line bevel wouldn't be visible,
+ // just draw a miter join to save a triangle.
+ if (miterLength < miterLimit) {
+ currentJoin = JoinType::Miter;
+ }
+ }
}
- else if (currentJoin == JoinType::Miter) {
- // MITER JOIN
- if (std::fabs(joinAngularity) < 0.01) {
- // The two normals are almost parallel.
- joinNormal.x = -nextNormal.y;
- joinNormal.y = nextNormal.x;
- } else if (roundness > layout.miter_limit) {
- // If the miter grows too large, flip the direction to make a
- // bevel join.
- joinNormal.x = (prevNormal.x - nextNormal.x) / joinAngularity;
- joinNormal.y = (prevNormal.y - nextNormal.y) / joinAngularity;
+ if (middleVertex && currentJoin == JoinType::Miter) {
+ joinNormal = joinNormal * miterLength;
+ addCurrentVertex(currentVertex, flip, distance, joinNormal, 0, 0, false, startVertex,
+ triangleStore);
+
+ } else if (middleVertex && currentJoin == JoinType::FlipBevel) {
+ // miter is too big, flip the direction to make a beveled join
+
+ if (miterLength > 100) {
+ // Almost parallel lines
+ joinNormal = nextNormal;
+ } else {
+ const float bevelLength = miterLength * util::mag(prevNormal + nextNormal) /
+ util::mag(prevNormal - nextNormal);
+ joinNormal = util::perp(joinNormal) * bevelLength;
}
- if (roundness > layout.miter_limit) {
- flip = -flip;
+ addCurrentVertex(currentVertex, flip, distance, joinNormal, 0, 0, false, startVertex,
+ triangleStore);
+ flip = -flip;
+
+ } else if (middleVertex && currentJoin == JoinType::Bevel) {
+ const float dir = prevNormal.x * nextNormal.y - prevNormal.y * nextNormal.x;
+ const float offset = -std::sqrt(miterLength * miterLength - 1);
+ float offsetA;
+ float offsetB;
+
+ if (flip * dir > 0) {
+ offsetB = 0;
+ offsetA = offset;
+ } else {
+ offsetA = 0;
+ offsetB = offset;
}
- // Add first vertex
- e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
- flip * joinNormal.x, flip * joinNormal.y, // extrude normal
- 0, 0, distance) - start_vertex; // texture normal
-
- if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
- e1 = e2; e2 = e3;
+ // Close previous segement with bevel
+ if (!startOfLine) {
+ addCurrentVertex(currentVertex, flip, distance, prevNormal, offsetA, offsetB, false,
+ startVertex, triangleStore);
+ }
- // Add second vertex
- e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
- -flip * joinNormal.x, -flip * joinNormal.y, // extrude normal
- 0, 1, distance) - start_vertex; // texture normal
+ // Start next segment
+ if (nextVertex) {
+ addCurrentVertex(currentVertex, flip, distance, nextNormal, -offsetA, -offsetB,
+ false, startVertex, triangleStore);
+ }
- if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
- e1 = e2; e2 = e3;
+ } else if (!middleVertex && currentCap == CapType::Butt) {
+ if (!startOfLine) {
+ // Close previous segment with a butt
+ addCurrentVertex(currentVertex, flip, distance, prevNormal, 0, 0, false,
+ startVertex, triangleStore);
+ }
- if ((!prevVertex && beginCap == CapType::Round) ||
- (!nextVertex && endCap == CapType::Round)) {
- point_store.emplace_back(e1);
+ // Start next segment with a butt
+ if (nextVertex) {
+ addCurrentVertex(currentVertex, flip, distance, nextNormal, 0, 0, false,
+ startVertex, triangleStore);
}
- }
- else {
- // Close up the previous line
- // Add first vertex
- e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
- flip * prevNormal.y, -flip * prevNormal.x, // extrude normal
- 0, 0, distance) - start_vertex; // texture normal
+ } else if (!middleVertex && currentCap == CapType::Square) {
+ if (!startOfLine) {
+ // Close previous segment with a square cap
+ addCurrentVertex(currentVertex, flip, distance, prevNormal, 1, 1, false,
+ startVertex, triangleStore);
- if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
- e1 = e2; e2 = e3;
+ // The segment is done. Unset vertices to disconnect segments.
+ e1 = e2 = -1;
+ flip = 1;
+ }
- // Add second vertex.
- e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
- -flip * prevNormal.y, flip * prevNormal.x, // extrude normal
- 0, 1, distance) - start_vertex; // texture normal
+ // Start next segment
+ if (nextVertex) {
+ addCurrentVertex(currentVertex, flip, distance, nextNormal, -1, -1, false,
+ startVertex, triangleStore);
+ }
- if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
- e1 = e2; e2 = e3;
+ } else if (middleVertex ? currentJoin == JoinType::Round : currentCap == CapType::Round) {
+ if (!startOfLine) {
+ // Close previous segment with a butt
+ addCurrentVertex(currentVertex, flip, distance, prevNormal, 0, 0, false,
+ startVertex, triangleStore);
- prevNormal = { -nextNormal.x, -nextNormal.y };
- flip = 1;
+ // Add round cap or linejoin at end of segment
+ addCurrentVertex(currentVertex, flip, distance, prevNormal, 1, 1, true, startVertex,
+ triangleStore);
+ // The segment is done. Unset vertices to disconnect segments.
+ e1 = e2 = -1;
+ flip = 1;
- // begin/end caps
- if ((!prevVertex && beginCap == CapType::Round) ||
- (!nextVertex && endCap == CapType::Round)) {
- point_store.emplace_back(e1);
+ } else if (beginCap == CapType::Round) {
+ // Add round cap before first segment
+ addCurrentVertex(currentVertex, flip, distance, nextNormal, -1, -1, true,
+ startVertex, triangleStore);
}
-
- if (currentJoin == JoinType::Round) {
- if (prevVertex && nextVertex && (!closed || i > 0)) {
- point_store.emplace_back(e1);
- }
-
- // Reset the previous vertices so that we don't accidentally create
- // any triangles.
- e1 = -1; e2 = -1; e3 = -1;
+ // Start next segment with a butt
+ if (nextVertex) {
+ addCurrentVertex(currentVertex, flip, distance, nextNormal, 0, 0, false,
+ startVertex, triangleStore);
}
-
- // Start the new quad.
- // Add first vertex
- e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
- -flip * nextNormal.y, flip * nextNormal.x, // extrude normal
- 0, 0, distance) - start_vertex; // texture normal
-
- if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
- e1 = e2; e2 = e3;
-
- // Add second vertex
- e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
- flip * nextNormal.y, -flip * nextNormal.x, // extrude normal
- 0, 1, distance) - start_vertex; // texture normal
-
- if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
- e1 = e2; e2 = e3;
}
+
+ startOfLine = false;
}
- size_t end_vertex = vertexBuffer.index();
- size_t vertex_count = end_vertex - start_vertex;
+ const size_t endVertex = vertexBuffer.index();
+ const size_t vertexCount = endVertex - startVertex;
// Store the triangle/line groups.
{
- if (!triangleGroups.size() || (triangleGroups.back()->vertex_length + vertex_count > 65535)) {
+ if (!triangleGroups.size() ||
+ (triangleGroups.back()->vertex_length + vertexCount > 65535)) {
// Move to a new group because the old one can't hold the geometry.
- triangleGroups.emplace_back(util::make_unique<triangle_group_type>());
+ triangleGroups.emplace_back(util::make_unique<TriangleGroup>());
}
assert(triangleGroups.back());
- triangle_group_type& group = *triangleGroups.back();
- for (const auto& triangle : triangle_store) {
- triangleElementsBuffer.add(
- group.vertex_length + triangle.a,
- group.vertex_length + triangle.b,
- group.vertex_length + triangle.c
- );
+ auto& group = *triangleGroups.back();
+ for (const auto& triangle : triangleStore) {
+ triangleElementsBuffer.add(group.vertex_length + triangle.a,
+ group.vertex_length + triangle.b,
+ group.vertex_length + triangle.c);
}
- group.vertex_length += vertex_count;
- group.elements_length += triangle_store.size();
+ group.vertex_length += vertexCount;
+ group.elements_length += triangleStore.size();
}
+}
- // Store the line join/cap groups.
- {
- if (!pointGroups.size() || (pointGroups.back()->vertex_length + vertex_count > 65535)) {
- // Move to a new group because the old one can't hold the geometry.
- pointGroups.emplace_back(util::make_unique<point_group_type>());
- }
-
- assert(pointGroups.back());
- point_group_type& group = *pointGroups.back();
- for (const auto point : point_store) {
- pointElementsBuffer.add(group.vertex_length + point);
- }
-
- group.vertex_length += vertex_count;
- group.elements_length += point_store.size();
+void LineBucket::addCurrentVertex(const Coordinate& currentVertex,
+ float flip,
+ double distance,
+ const vec2<double>& normal,
+ float endLeft,
+ float endRight,
+ bool round,
+ int32_t startVertex,
+ std::vector<TriangleElement>& triangleStore) {
+ int8_t tx = round ? 1 : 0;
+
+ vec2<double> extrude = normal * flip;
+ if (endLeft)
+ extrude = extrude - (util::perp(normal) * endLeft);
+ e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, extrude.x, extrude.y, tx, 0,
+ distance) -
+ startVertex;
+ if (e1 >= 0 && e2 >= 0) {
+ triangleStore.emplace_back(e1, e2, e3);
}
+ e1 = e2;
+ e2 = e3;
+
+ extrude = normal * (-flip);
+ if (endRight)
+ extrude = extrude - (util::perp(normal) * endRight);
+ e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, extrude.x, extrude.y, tx, 1,
+ distance) -
+ startVertex;
+ if (e1 >= 0 && e2 >= 0) {
+ triangleStore.emplace_back(e1, e2, e3);
+ }
+ e1 = e2;
+ e2 = e3;
}
-void LineBucket::render(Painter &painter, const StyleLayer &layer_desc, const TileID &id,
- const mat4 &matrix) {
+void LineBucket::render(Painter& painter,
+ const StyleLayer& layer_desc,
+ const TileID& id,
+ const mat4& matrix) {
painter.renderLine(*this, layer_desc, id, matrix);
}
bool LineBucket::hasData() const {
- return !triangleGroups.empty() || !pointGroups.empty();
-}
-
-bool LineBucket::hasPoints() const {
- if (!pointGroups.empty()) {
- for (const auto& group : pointGroups) {
- assert(group);
- if (group->elements_length) {
- return true;
- }
- }
- }
- return false;
+ return !triangleGroups.empty();
}
void LineBucket::drawLines(LineShader& shader) {
- char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize);
- char *elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize);
+ char* vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize);
+ char* elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize);
for (auto& group : triangleGroups) {
assert(group);
if (!group->elements_length) {
continue;
}
group->array[0].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index);
- MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
+ MBGL_CHECK_ERROR(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;
}
}
void LineBucket::drawLineSDF(LineSDFShader& shader) {
- char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize);
- char *elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize);
+ char* vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize);
+ char* elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize);
for (auto& group : triangleGroups) {
assert(group);
if (!group->elements_length) {
continue;
}
group->array[2].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index);
- MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
+ MBGL_CHECK_ERROR(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;
}
}
void LineBucket::drawLinePatterns(LinepatternShader& shader) {
- char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize);
- char *elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize);
+ char* vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize);
+ char* elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize);
for (auto& group : triangleGroups) {
assert(group);
if (!group->elements_length) {
continue;
}
group->array[1].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index);
- MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
+ MBGL_CHECK_ERROR(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;
}
}
-
-void LineBucket::drawPoints(LinejoinShader& shader) {
- char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize);
- char *elements_index = BUFFER_OFFSET(point_elements_start * pointElementsBuffer.itemSize);
- for (auto& group : pointGroups) {
- assert(group);
- if (!group->elements_length) {
- continue;
- }
- group->array[0].bind(shader, vertexBuffer, pointElementsBuffer, vertex_index);
- MBGL_CHECK_ERROR(glDrawElements(GL_POINTS, group->elements_length, GL_UNSIGNED_SHORT, elements_index));
- vertex_index += group->vertex_length * vertexBuffer.itemSize;
- elements_index += group->elements_length * pointElementsBuffer.itemSize;
- }
-}
diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/line_bucket.hpp
index d70801e0bf..64f353d7c4 100644
--- a/src/mbgl/renderer/line_bucket.hpp
+++ b/src/mbgl/renderer/line_bucket.hpp
@@ -18,18 +18,14 @@ class Style;
class LineVertexBuffer;
class TriangleElementsBuffer;
class LineShader;
-class LinejoinShader;
class LineSDFShader;
class LinepatternShader;
class LineBucket : public Bucket {
- typedef ElementGroup<3> triangle_group_type;
- typedef ElementGroup<1> point_group_type;
+ using TriangleGroup = ElementGroup<3>;
public:
- LineBucket(LineVertexBuffer &vertexBuffer,
- TriangleElementsBuffer &triangleElementsBuffer,
- PointElementsBuffer &pointElementsBuffer);
+ LineBucket(LineVertexBuffer &vertexBuffer, TriangleElementsBuffer &triangleElementsBuffer);
~LineBucket() override;
void render(Painter &painter, const StyleLayer &layer_desc, const TileID &id,
@@ -39,12 +35,18 @@ public:
void addGeometry(const GeometryCollection&);
void addGeometry(const std::vector<Coordinate>& line);
- bool hasPoints() const;
-
void drawLines(LineShader& shader);
void drawLineSDF(LineSDFShader& shader);
void drawLinePatterns(LinepatternShader& shader);
- void drawPoints(LinejoinShader& shader);
+
+private:
+ struct TriangleElement {
+ TriangleElement(uint16_t a_, uint16_t b_, uint16_t c_) : a(a_), b(b_), c(c_) {}
+ uint16_t a, b, c;
+ };
+ 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);
public:
StyleLayoutLine layout;
@@ -52,14 +54,15 @@ public:
private:
LineVertexBuffer& vertexBuffer;
TriangleElementsBuffer& triangleElementsBuffer;
- PointElementsBuffer& pointElementsBuffer;
const size_t vertex_start;
const size_t triangle_elements_start;
- const size_t point_elements_start;
- std::vector<std::unique_ptr<triangle_group_type>> triangleGroups;
- std::vector<std::unique_ptr<point_group_type>> pointGroups;
+ int32_t e1;
+ int32_t e2;
+ int32_t e3;
+
+ std::vector<std::unique_ptr<TriangleGroup>> triangleGroups;
};
}
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp
index cafd614244..1e34f53203 100644
--- a/src/mbgl/renderer/painter.cpp
+++ b/src/mbgl/renderer/painter.cpp
@@ -62,7 +62,6 @@ void Painter::setup() {
assert(plainShader);
assert(outlineShader);
assert(lineShader);
- assert(linejoinShader);
assert(linepatternShader);
assert(patternShader);
assert(rasterShader);
@@ -96,7 +95,6 @@ void Painter::setupShaders() {
if (!plainShader) plainShader = util::make_unique<PlainShader>();
if (!outlineShader) outlineShader = util::make_unique<OutlineShader>();
if (!lineShader) lineShader = util::make_unique<LineShader>();
- if (!linejoinShader) linejoinShader = util::make_unique<LinejoinShader>();
if (!linesdfShader) linesdfShader = util::make_unique<LineSDFShader>();
if (!linepatternShader) linepatternShader = util::make_unique<LinepatternShader>();
if (!patternShader) patternShader = util::make_unique<PatternShader>();
@@ -112,7 +110,6 @@ void Painter::deleteShaders() {
plainShader = nullptr;
outlineShader = nullptr;
lineShader = nullptr;
- linejoinShader = nullptr;
linepatternShader = nullptr;
patternShader = nullptr;
iconShader = nullptr;
diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp
index cf01c03918..76cacba43d 100644
--- a/src/mbgl/renderer/painter.hpp
+++ b/src/mbgl/renderer/painter.hpp
@@ -13,7 +13,6 @@
#include <mbgl/shader/outline_shader.hpp>
#include <mbgl/shader/pattern_shader.hpp>
#include <mbgl/shader/line_shader.hpp>
-#include <mbgl/shader/linejoin_shader.hpp>
#include <mbgl/shader/linesdf_shader.hpp>
#include <mbgl/shader/linepattern_shader.hpp>
#include <mbgl/shader/icon_shader.hpp>
@@ -199,7 +198,6 @@ public:
std::unique_ptr<PlainShader> plainShader;
std::unique_ptr<OutlineShader> outlineShader;
std::unique_ptr<LineShader> lineShader;
- std::unique_ptr<LinejoinShader> linejoinShader;
std::unique_ptr<LineSDFShader> linesdfShader;
std::unique_ptr<LinepatternShader> linepatternShader;
std::unique_ptr<PatternShader> patternShader;
diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp
index 2f8c3face3..57690da46f 100644
--- a/src/mbgl/renderer/painter_line.cpp
+++ b/src/mbgl/renderer/painter_line.cpp
@@ -51,29 +51,6 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const
depthRange(strata, 1.0f);
- // We're only drawing end caps + round line joins if the line is > 2px. Otherwise, they aren't visible anyway.
- if (bucket.hasPoints() && outset > 1.0f) {
- useProgram(linejoinShader->program);
- linejoinShader->u_matrix = vtxMatrix;
- linejoinShader->u_color = color;
- linejoinShader->u_world = {{
- state.getFramebufferWidth() * 0.5f,
- state.getFramebufferHeight() * 0.5f
- }};
- linejoinShader->u_linewidth = {{
- ((outset - 0.25f) * state.getPixelRatio()),
- ((inset - 0.25f) * state.getPixelRatio())
- }};
-
- float pointSize = std::ceil(state.getPixelRatio() * outset * 2.0);
-#if defined(GL_ES_VERSION_2_0)
- linejoinShader->u_size = pointSize;
-#else
- MBGL_CHECK_ERROR(glPointSize(pointSize));
-#endif
- bucket.drawPoints(*linejoinShader);
- }
-
if (properties.dash_array.from.size()) {
useProgram(linesdfShader->program);
diff --git a/src/mbgl/shader/linejoin.fragment.glsl b/src/mbgl/shader/linejoin.fragment.glsl
deleted file mode 100644
index 705a57766e..0000000000
--- a/src/mbgl/shader/linejoin.fragment.glsl
+++ /dev/null
@@ -1,14 +0,0 @@
-uniform vec4 u_color;
-uniform vec2 u_linewidth;
-
-varying vec2 v_pos;
-
-void main() {
- float dist = length(v_pos - gl_FragCoord.xy);
-
- // Calculate the antialiasing fade factor. This is either when fading in
- // the line in case of an offset line (v_linewidth.t) or when fading out
- // (v_linewidth.s)
- float alpha = clamp(min(dist - (u_linewidth.t - 1.0), u_linewidth.s - dist), 0.0, 1.0);
- gl_FragColor = u_color * alpha;
-}
diff --git a/src/mbgl/shader/linejoin.vertex.glsl b/src/mbgl/shader/linejoin.vertex.glsl
deleted file mode 100644
index 2e03561e5b..0000000000
--- a/src/mbgl/shader/linejoin.vertex.glsl
+++ /dev/null
@@ -1,13 +0,0 @@
-attribute vec2 a_pos;
-
-uniform mat4 u_matrix;
-uniform vec2 u_world;
-uniform float u_size;
-
-varying vec2 v_pos;
-
-void main() {
- gl_Position = u_matrix * vec4(floor(a_pos / 2.0), 0.0, 1.0);
- v_pos = (gl_Position.xy + 1.0) * u_world;
- gl_PointSize = u_size;
-}
diff --git a/src/mbgl/shader/linejoin_shader.cpp b/src/mbgl/shader/linejoin_shader.cpp
deleted file mode 100644
index b3c5638b5d..0000000000
--- a/src/mbgl/shader/linejoin_shader.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#include <mbgl/shader/linejoin_shader.hpp>
-#include <mbgl/shader/shaders.hpp>
-#include <mbgl/platform/gl.hpp>
-
-#include <cstdio>
-
-using namespace mbgl;
-
-LinejoinShader::LinejoinShader()
- : Shader(
- "linejoin",
- shaders[LINEJOIN_SHADER].vertex,
- shaders[LINEJOIN_SHADER].fragment
- ) {
- a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_pos"));
-}
-
-void LinejoinShader::bind(char *offset) {
- MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_pos));
- // Note: We're referring to the vertices in a line array, which are 8 bytes long!
- MBGL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 8, offset));
-}
diff --git a/src/mbgl/shader/linejoin_shader.hpp b/src/mbgl/shader/linejoin_shader.hpp
deleted file mode 100644
index 61406fd45c..0000000000
--- a/src/mbgl/shader/linejoin_shader.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef MBGL_SHADER_SHADER_LINEJOIN
-#define MBGL_SHADER_SHADER_LINEJOIN
-
-#include <mbgl/shader/shader.hpp>
-#include <mbgl/shader/uniform.hpp>
-
-namespace mbgl {
-
-class LinejoinShader : public Shader {
-public:
- LinejoinShader();
-
- void bind(char *offset);
-
- UniformMatrix<4> u_matrix = {"u_matrix", *this};
- Uniform<std::array<float, 4>> u_color = {"u_color", *this};
- Uniform<std::array<float, 2>> u_world = {"u_world", *this};
- Uniform<std::array<float, 2>> u_linewidth = {"u_linewidth", *this};
- Uniform<float> u_size = {"u_size", *this};
-
-private:
- int32_t a_pos = -1;
-};
-
-}
-
-#endif
diff --git a/src/mbgl/style/types.hpp b/src/mbgl/style/types.hpp
index 3b24d63998..f6ffcd6865 100644
--- a/src/mbgl/style/types.hpp
+++ b/src/mbgl/style/types.hpp
@@ -91,13 +91,15 @@ MBGL_DEFINE_ENUM_CLASS(CapTypeClass, CapType, {
enum class JoinType : uint8_t {
Miter,
Bevel,
- Round
+ Round,
+ FlipBevel
};
MBGL_DEFINE_ENUM_CLASS(JoinTypeClass, JoinType, {
{ JoinType::Miter, "miter" },
{ JoinType::Bevel, "bevel" },
{ JoinType::Round, "round" },
+ { JoinType::FlipBevel, "flipbevel" },
});
// -------------------------------------------------------------------------------------------------