diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2015-04-27 12:22:24 +0200 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2015-04-27 12:22:24 +0200 |
commit | 99ab9c3c6debdf492aff7a751d82400eba1b1cdf (patch) | |
tree | 568e06c10643f5554a3cd00418a3d44f51bf5855 | |
parent | 8aa2e2fef76eb4dfdb6e5b28a815babd27647322 (diff) | |
parent | feade7b4e42bf8d293d5023dc12ea2f9106e3b7c (diff) | |
download | qtlocation-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.hpp | 10 | ||||
-rw-r--r-- | include/mbgl/util/vec.hpp | 8 | ||||
-rw-r--r-- | src/mbgl/geometry/elements_buffer.cpp | 5 | ||||
-rw-r--r-- | src/mbgl/geometry/elements_buffer.hpp | 10 | ||||
-rw-r--r-- | src/mbgl/map/tile_parser.cpp | 3 | ||||
-rw-r--r-- | src/mbgl/map/vector_tile_data.hpp | 1 | ||||
-rw-r--r-- | src/mbgl/renderer/line_bucket.cpp | 506 | ||||
-rw-r--r-- | src/mbgl/renderer/line_bucket.hpp | 29 | ||||
-rw-r--r-- | src/mbgl/renderer/painter.cpp | 3 | ||||
-rw-r--r-- | src/mbgl/renderer/painter.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/painter_line.cpp | 23 | ||||
-rw-r--r-- | src/mbgl/shader/linejoin.fragment.glsl | 14 | ||||
-rw-r--r-- | src/mbgl/shader/linejoin.vertex.glsl | 13 | ||||
-rw-r--r-- | src/mbgl/shader/linejoin_shader.cpp | 22 | ||||
-rw-r--r-- | src/mbgl/shader/linejoin_shader.hpp | 27 | ||||
-rw-r--r-- | src/mbgl/style/types.hpp | 4 |
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" }, }); // ------------------------------------------------------------------------------------------------- |