diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2014-02-11 15:51:54 +0100 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2014-02-11 15:51:54 +0100 |
commit | bec0ad10c4b460941d08cca597bf352c96820d34 (patch) | |
tree | 39fd506db5deeeedc8aebc51b124e6a68ddd7de4 | |
parent | eb9a6b7068b9910301bfc7a3b83e114c7545c893 (diff) | |
download | qtlocation-mapboxgl-bec0ad10c4b460941d08cca597bf352c96820d34.tar.gz |
drawing lines with triangles
34 files changed, 448 insertions, 259 deletions
@@ -19,6 +19,11 @@ app: config.gypi src macosx/llmr-app.gyp xcode: config.gypi llmr.gyp deps/run_gyp llmr.gyp -Goutput_dir=./out/ --depth=. --generator-output=./ -f xcode +# build OS X app with Xcode +xproj: config.gypi src macosx/llmr-app.gyp + deps/run_gyp macosx/llmr-app.gyp -Goutput_dir=./out/ --depth=. --generator-output=./ -f xcode + open ./macosx/llmr-app.xcodeproj + # build OS X app with xcodebuild xapp: config.gypi src macosx/llmr-app.gyp deps/run_gyp macosx/llmr-app.gyp -Goutput_dir=./out/ --depth=. --generator-output=./ -f xcode diff --git a/bin/convert-style.js b/bin/convert-style.js index da9a95a428..2f21d6a8bf 100755 --- a/bin/convert-style.js +++ b/bin/convert-style.js @@ -25,7 +25,7 @@ var cap_type = { // enum var join_type = { - butt: 1, + miter: 1, bevel: 2, round: 3 }; diff --git a/bin/style.js b/bin/style.js index 4099b420d4..1596e30a67 100644 --- a/bin/style.js +++ b/bin/style.js @@ -10,17 +10,17 @@ module.exports = { "road_large": { "datasource": "streets", "layer": "road", "field": "class", "value": ["motorway", "main"], - "type": "line", "cap": "round", "join": "bevel" + "type": "line", "cap": "round", "join": "round" }, "road_regular": { "datasource": "streets", "layer": "road", "field": "class", "value": "street", - "type": "line", "cap": "round", "join": "bevel" + "type": "line", "cap": "round", "join": "round" }, "road_limited": { "datasource": "streets", "layer": "road", "field": "class", "value": "street_limited", - "type": "line", "cap": "round", "join": "bevel" + "type": "line", "cap": "round", "join": "round" }, "park": { "datasource": "streets", diff --git a/include/llmr/geometry/buffer.hpp b/include/llmr/geometry/buffer.hpp index 1177bb196e..1b9e5c6307 100644 --- a/include/llmr/geometry/buffer.hpp +++ b/include/llmr/geometry/buffer.hpp @@ -8,7 +8,7 @@ namespace llmr { template < - size_t itemSize, + size_t item_size, int bufferType = GL_ARRAY_BUFFER, size_t defaultLength = 8192 > @@ -44,6 +44,7 @@ public: } } + protected: // increase the buffer size by at least /required/ bytes. void *addElement() { @@ -57,6 +58,9 @@ protected: return static_cast<char *>(array) + (pos - itemSize); } +public: + const size_t itemSize = item_size; + private: // CPU buffer void *array = nullptr; diff --git a/include/llmr/geometry/elements_buffer.hpp b/include/llmr/geometry/elements_buffer.hpp new file mode 100644 index 0000000000..82d97f8b6d --- /dev/null +++ b/include/llmr/geometry/elements_buffer.hpp @@ -0,0 +1,30 @@ +#ifndef LLMR_GEOMETRY_TRIANGLE_ELEMENTS_BUFFER +#define LLMR_GEOMETRY_TRIANGLE_ELEMENTS_BUFFER + +#include "buffer.hpp" + +namespace llmr { + +class TriangleElementsBuffer : public Buffer< + 6, // bytes per triangle (3 * unsigned short == 6 bytes) + GL_ELEMENT_ARRAY_BUFFER +> { +public: + typedef uint16_t element_type; + + void add(element_type a, element_type b, element_type c); +}; + +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/include/llmr/geometry/fill_buffer.hpp b/include/llmr/geometry/fill_buffer.hpp index f413715042..90265b8b97 100644 --- a/include/llmr/geometry/fill_buffer.hpp +++ b/include/llmr/geometry/fill_buffer.hpp @@ -7,7 +7,6 @@ namespace llmr { - class FillVertexBuffer : public Buffer< 4 // bytes per coordinates (2 * unsigned short == 4 bytes) > { @@ -18,17 +17,6 @@ public: void add(vertex_type x, vertex_type y); }; - -class FillElementsBuffer : public Buffer< - 6, // bytes per triangle (3 * unsigned short == 6 bytes) - GL_ELEMENT_ARRAY_BUFFER -> { -public: - typedef uint16_t element_type; - - void add(element_type a, element_type b, element_type c); -}; - } #endif diff --git a/include/llmr/geometry/line_buffer.hpp b/include/llmr/geometry/line_buffer.hpp index ccbdce1191..a18ea810ae 100644 --- a/include/llmr/geometry/line_buffer.hpp +++ b/include/llmr/geometry/line_buffer.hpp @@ -5,8 +5,7 @@ namespace llmr { - -class LineBuffer : public Buffer< +class LineVertexBuffer : public Buffer< 8 // 2 coordinates per vertex + 1 linesofar + 1 extrude coord pair == 4 (== 8 bytes) > { public: @@ -31,20 +30,10 @@ public: * @param {number} tx texture normal * @param {number} ty texture normal */ - void add(vertex_type x, vertex_type y, float ex, float ey, int8_t tx, int8_t ty, int32_t linesofar = 0); - - /* - * Add a degenerate triangle to the buffer - * - * > So we need a way to get from the end of one triangle strip - * to the beginning of the next strip without actually filling triangles - * on the way. We can do this with "degenerate" triangles: We simply - * repeat the last coordinate of the first triangle strip and the first - * coordinate of the next triangle strip. - */ - void addDegenerate(); + size_t add(vertex_type x, vertex_type y, float ex, float ey, int8_t tx, int8_t ty, int32_t linesofar = 0); }; + } #endif diff --git a/include/llmr/geometry/vao.hpp b/include/llmr/geometry/vao.hpp index 49401e01d2..a2a5a8a0d0 100644 --- a/include/llmr/geometry/vao.hpp +++ b/include/llmr/geometry/vao.hpp @@ -10,19 +10,47 @@ namespace llmr { template <typename Shader> class VertexArrayObject { public: - template <typename Buffer> - void bind(Shader& shader, Buffer& buffer, char *offset) { + template <typename VertexBuffer> + void bind(Shader& shader, VertexBuffer& vertex_buffer, char *offset) { if (!vao) { glGenVertexArrays(1, &vao); glBindVertexArray(vao); - buffer.bind(); + vertex_buffer.bind(); shader.bind(offset); - buffer_ptr = &buffer; + vertex_buffer_ptr = &vertex_buffer; + elements_buffer_ptr = nullptr; offset_ptr = offset; - } else if (buffer_ptr != &buffer) { - throw std::runtime_error("trying to bind VAO to another buffer"); + } else if (vertex_buffer_ptr != &vertex_buffer) { + throw std::runtime_error("trying to bind VAO to another vertex buffer"); + } else if (elements_buffer_ptr != nullptr) { + throw std::runtime_error("trying to bind VAO to another elements buffer"); + } else if (offset_ptr != offset) { + throw std::runtime_error("trying to bind VAO to another offset"); + } else { + // We have been given the correct information. + glBindVertexArray(vao); + } + } + + template <typename VertexBuffer, typename ElementsBuffer> + void bind(Shader& shader, VertexBuffer& vertex_buffer, ElementsBuffer& elements_buffer, char *offset) { + if (!vao) { + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + vertex_buffer.bind(); + elements_buffer.bind(); + shader.bind(offset); + + vertex_buffer_ptr = &vertex_buffer; + elements_buffer_ptr = &elements_buffer; + offset_ptr = offset; + } else if (vertex_buffer_ptr != &vertex_buffer) { + throw std::runtime_error("trying to bind VAO to another vertex buffer"); + } else if (elements_buffer_ptr != &elements_buffer) { + throw std::runtime_error("trying to bind VAO to another elements buffer"); } else if (offset_ptr != offset) { throw std::runtime_error("trying to bind VAO to another offset"); } else { @@ -42,7 +70,8 @@ private: // For debug reasons, we're storing the bind information so that we can // detect errors and report - void *buffer_ptr = nullptr; + void *vertex_buffer_ptr = nullptr; + void *elements_buffer_ptr = nullptr; char *offset_ptr = 0; }; diff --git a/include/llmr/map/tile.hpp b/include/llmr/map/tile.hpp index d0d660a4e6..4b2aed8885 100644 --- a/include/llmr/map/tile.hpp +++ b/include/llmr/map/tile.hpp @@ -22,8 +22,9 @@ class BucketDescription; class VectorTile; class VectorTileLayer; class FillVertexBuffer; -class FillElementsBuffer; -class LineBuffer; +class LineVertexBuffer; +class TriangleElementsBuffer; +class PointElementsBuffer; class PlainShader; class Tile : public std::enable_shared_from_this<Tile>, @@ -74,8 +75,9 @@ public: VertexArrayObject<PlainShader> debugFontArray; std::shared_ptr<FillVertexBuffer> fillVertexBuffer; - std::shared_ptr<FillElementsBuffer> fillElementsBuffer; - std::shared_ptr<LineBuffer> lineBuffer; + std::shared_ptr<LineVertexBuffer> lineVertexBuffer; + std::shared_ptr<TriangleElementsBuffer> triangleElementsBuffer; + std::shared_ptr<PointElementsBuffer> pointElementsBuffer; // Holds the buckets of this tile. // They contain the location offsets in the buffers stored above diff --git a/include/llmr/renderer/fill_bucket.hpp b/include/llmr/renderer/fill_bucket.hpp index 2992d77109..e8b278b329 100644 --- a/include/llmr/renderer/fill_bucket.hpp +++ b/include/llmr/renderer/fill_bucket.hpp @@ -17,7 +17,7 @@ namespace llmr { class Style; class FillVertexBuffer; -class FillElementsBuffer; +class TriangleElementsBuffer; class BucketDescription; class OutlineShader; class PlainShader; @@ -27,7 +27,7 @@ struct pbf; class FillBucket : public Bucket { public: FillBucket(const std::shared_ptr<FillVertexBuffer>& vertexBuffer, - const std::shared_ptr<FillElementsBuffer>& elementsBuffer, + const std::shared_ptr<TriangleElementsBuffer>& elementsBuffer, const BucketDescription& bucket_desc); virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id); @@ -44,7 +44,7 @@ public: private: std::shared_ptr<FillVertexBuffer> vertexBuffer; - std::shared_ptr<FillElementsBuffer> elementsBuffer; + std::shared_ptr<TriangleElementsBuffer> elementsBuffer; struct group { VertexArrayObject<PlainShader> array; diff --git a/include/llmr/renderer/line_bucket.hpp b/include/llmr/renderer/line_bucket.hpp index 7d61af15e4..b94440cd69 100644 --- a/include/llmr/renderer/line_bucket.hpp +++ b/include/llmr/renderer/line_bucket.hpp @@ -10,34 +10,50 @@ namespace llmr { class Style; -class LineBuffer; +class LineVertexBuffer; +class TriangleElementsBuffer; class LineShader; +class LinejoinShader; struct Coordinate; struct pbf; class LineBucket : public Bucket { public: - LineBucket(const std::shared_ptr<LineBuffer>& buffer, const BucketDescription& bucket_desc); + LineBucket(const std::shared_ptr<LineVertexBuffer>& vertexBuffer, + const std::shared_ptr<TriangleElementsBuffer>& triangleElementsBuffer, + const std::shared_ptr<PointElementsBuffer>& pointElementsBuffer, + const BucketDescription& bucket_desc); virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id); void addGeometry(pbf& data); void addGeometry(const std::vector<Coordinate>& line); - size_t size() const; + bool empty() const; + bool hasPoints() const; - void bind(LineShader& shader); - void drawLines(); - void drawPoints(); + void drawLines(LineShader& shader); + void drawDebugLines(LineShader& shader); + void drawPoints(LinejoinShader& shader); public: const BucketGeometryDescription geometry; private: - std::shared_ptr<LineBuffer> buffer; - uint32_t start; - uint32_t length; - VertexArrayObject<LineShader> array; + std::shared_ptr<LineVertexBuffer> vertexBuffer; + const uint32_t vertex_start; + uint32_t vertex_length; + + std::shared_ptr<TriangleElementsBuffer> triangleElementsBuffer; + const uint32_t triangle_elements_start; + uint32_t triangle_length; + + std::shared_ptr<PointElementsBuffer> pointElementsBuffer; + const uint32_t point_elements_start; + uint32_t point_length; + + VertexArrayObject<LineShader> lineArray; + VertexArrayObject<LinejoinShader> pointArray; }; } diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index 925defd035..fed7128fc2 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -11,6 +11,7 @@ #include <llmr/renderer/shader-outline.hpp> #include <llmr/renderer/shader-pattern.hpp> #include <llmr/renderer/shader-line.hpp> +#include <llmr/renderer/shader-linejoin.hpp> namespace llmr { @@ -54,6 +55,7 @@ private: std::unique_ptr<PlainShader> plainShader; std::unique_ptr<OutlineShader> outlineShader; std::unique_ptr<LineShader> lineShader; + std::unique_ptr<LinejoinShader> linejoinShader; std::unique_ptr<PatternShader> patternShader; // Set up the stencil quad we're using to generate the stencil mask. diff --git a/include/llmr/renderer/shader-line.hpp b/include/llmr/renderer/shader-line.hpp index 00e50c1b1f..9c0dfbaba9 100644 --- a/include/llmr/renderer/shader-line.hpp +++ b/include/llmr/renderer/shader-line.hpp @@ -19,11 +19,9 @@ public: int32_t u_exmatrix; int32_t u_linewidth; int32_t u_color; - int32_t u_debug; int32_t u_ratio; int32_t u_dasharray; - int32_t u_point; - int32_t u_gamma; + int32_t u_debug; }; } diff --git a/include/llmr/renderer/shader-linejoin.hpp b/include/llmr/renderer/shader-linejoin.hpp new file mode 100644 index 0000000000..05993e8f72 --- /dev/null +++ b/include/llmr/renderer/shader-linejoin.hpp @@ -0,0 +1,24 @@ +#ifndef LLMR_RENDERER_SHADER_LINEJOIN +#define LLMR_RENDERER_SHADER_LINEJOIN + +#include "shader.hpp" + +namespace llmr { + +class LinejoinShader : public Shader { +public: + LinejoinShader(); + + void bind(char *offset); + + int32_t a_pos; + + int32_t u_matrix; + int32_t u_world; + int32_t u_linewidth; + int32_t u_color; +}; + +} + +#endif diff --git a/include/llmr/shader/shaders.hpp b/include/llmr/shader/shaders.hpp index d3007b2ccf..c0f02337a0 100644 --- a/include/llmr/shader/shaders.hpp +++ b/include/llmr/shader/shaders.hpp @@ -12,6 +12,7 @@ struct shader_source { enum { LINE_SHADER, + LINEJOIN_SHADER, OUTLINE_SHADER, PATTERN_SHADER, PLAIN_SHADER, diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index 9978cf364e..919d3db684 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -24,7 +24,7 @@ enum class CapType { enum class JoinType { None = 0, - Butt = 1, + Miter = 1, Bevel = 2, Round = 3 }; @@ -46,7 +46,7 @@ inline CapType capType(const std::string& cap) { inline JoinType joinType(const std::string& join) { - if (join == "butt") return JoinType::Butt; + if (join == "miter") return JoinType::Miter; else if (join == "bevel") return JoinType::Bevel; else if (join == "round") return JoinType::Round; else return JoinType::None; diff --git a/macosx/main.mm b/macosx/main.mm index b8f333ba23..db244da043 100644 --- a/macosx/main.mm +++ b/macosx/main.mm @@ -161,7 +161,11 @@ public: int run() { while (!glfwWindowShouldClose(window)) { if (dirty) { - dirty = render(); + try { + dirty = render(); + } catch(std::exception& ex) { + fprintf(stderr, "exception: %s\n", ex.what()); + } glfwSwapBuffers(window); fps(); } diff --git a/proto/style.proto b/proto/style.proto index 8459477bf7..90e5b65061 100644 --- a/proto/style.proto +++ b/proto/style.proto @@ -13,7 +13,7 @@ enum cap_type { } enum join_type { - butt_join = 1; + miter_join = 1; bevel_join = 2; round_join = 3; } diff --git a/resources/style.pbf b/resources/style.pbf Binary files differindex d87f896d1a..1b991386c7 100644 --- a/resources/style.pbf +++ b/resources/style.pbf diff --git a/src/geometry/elements_buffer.cpp b/src/geometry/elements_buffer.cpp new file mode 100644 index 0000000000..ea4c43644c --- /dev/null +++ b/src/geometry/elements_buffer.cpp @@ -0,0 +1,15 @@ +#include <llmr/geometry/elements_buffer.hpp> + +using namespace llmr; + +void TriangleElementsBuffer::add(element_type a, element_type b, element_type c) { + element_type *elements = static_cast<element_type *>(addElement()); + elements[0] = a; + elements[1] = b; + elements[2] = c; +} + +void PointElementsBuffer::add(element_type a) { + uint16_t *data = static_cast<element_type *>(addElement()); + data[0] = a; +} diff --git a/src/geometry/fill_buffer.cpp b/src/geometry/fill_buffer.cpp index 3de008a7a7..871c93ee06 100644 --- a/src/geometry/fill_buffer.cpp +++ b/src/geometry/fill_buffer.cpp @@ -16,10 +16,3 @@ void FillVertexBuffer::add(vertex_type x, vertex_type y) { vertices[0] = x; vertices[1] = y; } - -void FillElementsBuffer::add(element_type a, element_type b, element_type c) { - element_type *elements = static_cast<element_type *>(addElement()); - elements[0] = a; - elements[1] = b; - elements[2] = c; -} diff --git a/src/geometry/line_buffer.cpp b/src/geometry/line_buffer.cpp index b9c770c04a..598a34c824 100644 --- a/src/geometry/line_buffer.cpp +++ b/src/geometry/line_buffer.cpp @@ -5,7 +5,8 @@ using namespace llmr; -void LineBuffer::add(vertex_type x, vertex_type y, float ex, float ey, int8_t tx, int8_t ty, int32_t linesofar) { +size_t LineVertexBuffer::add(vertex_type x, vertex_type y, float ex, float ey, int8_t tx, int8_t ty, int32_t linesofar) { + size_t idx = index(); void *data = addElement(); int16_t *coords = static_cast<int16_t *>(data); @@ -16,8 +17,6 @@ void LineBuffer::add(vertex_type x, vertex_type y, float ex, float ey, int8_t tx int8_t *extrude = static_cast<int8_t *>(data); extrude[6] = round(extrudeScale * ex); extrude[7] = round(extrudeScale * ey); -}; -void LineBuffer::addDegenerate() { - add(16383, 16383, 0, 0, 1, 1, 0); + return idx; } diff --git a/src/map/tile.cpp b/src/map/tile.cpp index 016811af00..27ca2891eb 100644 --- a/src/map/tile.cpp +++ b/src/map/tile.cpp @@ -4,6 +4,7 @@ #include <llmr/map/vector_tile.hpp> #include <llmr/geometry/fill_buffer.hpp> #include <llmr/geometry/line_buffer.hpp> +#include <llmr/geometry/elements_buffer.hpp> #include <llmr/renderer/fill_bucket.hpp> #include <llmr/renderer/line_bucket.hpp> #include <llmr/platform/platform.hpp> @@ -43,8 +44,9 @@ Tile::Tile(ID id, const Style& style) : id(id), state(initial), fillVertexBuffer(std::make_shared<FillVertexBuffer>()), - fillElementsBuffer(std::make_shared<FillElementsBuffer>()), - lineBuffer(std::make_shared<LineBuffer>()), + lineVertexBuffer(std::make_shared<LineVertexBuffer>()), + triangleElementsBuffer(std::make_shared<TriangleElementsBuffer>()), + pointElementsBuffer(std::make_shared<PointElementsBuffer>()), style(style) { // Initialize tile debug coordinates @@ -167,7 +169,7 @@ std::shared_ptr<Bucket> Tile::createBucket(const VectorTile& tile, const BucketD } std::shared_ptr<Bucket> Tile::createFillBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { - std::shared_ptr<FillBucket> bucket = std::make_shared<FillBucket>(fillVertexBuffer, fillElementsBuffer, bucket_desc); + std::shared_ptr<FillBucket> bucket = std::make_shared<FillBucket>(fillVertexBuffer, triangleElementsBuffer, bucket_desc); FilteredVectorTileLayer filtered_layer(layer, bucket_desc); for (pbf feature : filtered_layer) { @@ -183,7 +185,7 @@ std::shared_ptr<Bucket> Tile::createFillBucket(const VectorTileLayer& layer, con } std::shared_ptr<Bucket> Tile::createLineBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { - std::shared_ptr<LineBucket> bucket = std::make_shared<LineBucket>(lineBuffer, bucket_desc); + std::shared_ptr<LineBucket> bucket = std::make_shared<LineBucket>(lineVertexBuffer, triangleElementsBuffer, pointElementsBuffer, bucket_desc); FilteredVectorTileLayer filtered_layer(layer, bucket_desc); for (pbf feature : filtered_layer) { diff --git a/src/renderer/fill_bucket.cpp b/src/renderer/fill_bucket.cpp index 8446c04f2b..2c52701742 100644 --- a/src/renderer/fill_bucket.cpp +++ b/src/renderer/fill_bucket.cpp @@ -1,5 +1,6 @@ #include <llmr/renderer/fill_bucket.hpp> #include <llmr/geometry/fill_buffer.hpp> +#include <llmr/geometry/elements_buffer.hpp> #include <llmr/geometry/geometry.hpp> #include <llmr/renderer/painter.hpp> @@ -15,7 +16,7 @@ struct geometry_too_long_exception : std::exception {}; using namespace llmr; FillBucket::FillBucket(const std::shared_ptr<FillVertexBuffer>& vertexBuffer, - const std::shared_ptr<FillElementsBuffer>& elementsBuffer, + const std::shared_ptr<TriangleElementsBuffer>& elementsBuffer, const BucketDescription& bucket_desc) : geom_desc(bucket_desc.geometry), vertexBuffer(vertexBuffer), @@ -102,14 +103,11 @@ uint32_t FillBucket::size() const { return length; } - - void FillBucket::drawElements(PlainShader& shader) { - char *vertex_index = BUFFER_OFFSET(vertex_start * 2 * sizeof(int16_t)); - char *elements_index = BUFFER_OFFSET(elements_start * 3 * sizeof(int16_t)); + char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer->itemSize); + char *elements_index = BUFFER_OFFSET(elements_start * elementsBuffer->itemSize); for (group& group : groups) { - group.array.bind(shader, *vertexBuffer, vertex_index); - elementsBuffer->bind(); + group.array.bind(shader, *vertexBuffer, *elementsBuffer, vertex_index); glDrawElements(GL_TRIANGLES, group.elements_length * 3 - 3, GL_UNSIGNED_SHORT, elements_index); vertex_index += group.vertex_length * 2 * sizeof(uint16_t); elements_index += group.elements_length * 3 * sizeof(uint16_t); diff --git a/src/renderer/line_bucket.cpp b/src/renderer/line_bucket.cpp index 213d8a2856..e60b4fa6f4 100644 --- a/src/renderer/line_bucket.cpp +++ b/src/renderer/line_bucket.cpp @@ -1,9 +1,11 @@ #include <llmr/renderer/line_bucket.hpp> #include <llmr/geometry/line_buffer.hpp> +#include <llmr/geometry/elements_buffer.hpp> #include <llmr/geometry/geometry.hpp> #include <llmr/renderer/painter.hpp> #include <llmr/renderer/shader-line.hpp> +#include <llmr/renderer/shader-linejoin.hpp> #include <llmr/style/style.hpp> #include <llmr/map/vector_tile.hpp> @@ -18,11 +20,20 @@ struct geometry_too_long_exception : std::exception {}; using namespace llmr; -LineBucket::LineBucket(const std::shared_ptr<LineBuffer>& buffer, const BucketDescription& bucket_desc) +LineBucket::LineBucket(const std::shared_ptr<LineVertexBuffer>& vertexBuffer, + const std::shared_ptr<TriangleElementsBuffer>& triangleElementsBuffer, + const std::shared_ptr<PointElementsBuffer>& pointElementsBuffer, + const BucketDescription& bucket_desc) : geometry(bucket_desc.geometry), - buffer(buffer), - start(buffer->index()), - length(0) { + vertexBuffer(vertexBuffer), + vertex_start(vertexBuffer->index()), + vertex_length(0), + triangleElementsBuffer(triangleElementsBuffer), + triangle_elements_start(triangleElementsBuffer->index()), + triangle_length(0), + pointElementsBuffer(pointElementsBuffer), + point_elements_start(pointElementsBuffer->index()), + point_length(0) { } void LineBucket::addGeometry(pbf& geom) { @@ -52,15 +63,8 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) { const float miterLimit = geometry.miter_limit; const float roundLimit = geometry.round_limit; - if (vertices.size() < 1) { - // alert('a line must have at least one vertex'); - return; - } - - // Point - if (vertices.size() == 1) { - Coordinate coord = vertices.front(); - buffer->add(coord.x, coord.y, 1, 0, 0, 0); + if (vertices.size() < 2) { + // fprintf(stderr, "a line must have at least two vertices\n"); return; } @@ -69,19 +73,23 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) { bool closed = firstVertex.x == lastVertex.x && firstVertex.y == lastVertex.y; if (vertices.size() == 2 && closed) { - // alert('a line may not have coincident points'); + // fprintf(stderr, "a line may not have coincident points\n"); return; } CapType beginCap = cap; CapType endCap = closed ? CapType::Butt : cap; + JoinType currentJoin = JoinType::None; + 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; + int8_t flip = 1; double distance = 0; @@ -90,14 +98,12 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) { nextNormal = util::normal<double>(currentVertex, lastVertex); } - // Start all lines with a degenerate vertex - buffer->addDegenerate(); - for (size_t i = 0; i < vertices.size(); ++i) { if (nextNormal) prevNormal = { -nextNormal.x, -nextNormal.y }; if (currentVertex) prevVertex = currentVertex; currentVertex = vertices[i]; + currentJoin = join; if (prevVertex) distance += util::dist<double>(currentVertex, prevVertex); @@ -108,18 +114,11 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) { nextVertex = Coordinate::null(); } - bool segment = false; - - if (closed && i >= 2 && (i + 1 < vertices.size())) { - segment = true; - } - // If the line is closed, we treat the last vertex like the first vertex. if (!nextVertex && closed) { nextVertex = vertices[1]; } - if (nextVertex) { // if two consecutive vertices exist, skip one if (currentVertex.x == nextVertex.x && currentVertex.y == nextVertex.y) continue; @@ -155,67 +154,53 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) { double roundness = fmax(abs(joinNormal.x), abs(joinNormal.y)); - bool roundJoin = false; - // Determine whether we should actually draw a round/bevelled/butt line join. It looks - // better if we do, but we can get away with drawing a mitered join for - // joins that have a very small angle. For this, we have the "roundLimit" - // parameter. We do this to reduce the number of vertices we have to - // write into the line vertex buffer. Note that joinAngularity may be 0, - // so the roundness grows to infinity. This is intended. - if ((join == JoinType::Round || join == JoinType::Bevel || join == JoinType::Butt) && roundness > roundLimit) { - roundJoin = true; + // Switch to miter joins if the angle is very low. + if (currentJoin != JoinType::Miter) { + if (fabs(joinAngularity) < 0.5 && roundness < miterLimit) { + currentJoin = JoinType::Miter; + } } - // Close up the previous line for a round join - if (roundJoin && prevVertex && nextVertex) { + // Add offset square begin cap. + if (!prevVertex && beginCap == CapType::Square) { // Add first vertex - buffer->add(currentVertex.x, currentVertex.y, // vertex pos - flip * prevNormal.y, -flip * prevNormal.x, // extrude normal - 0, 0, distance); // texture normal - - // Add second vertex. - buffer->add(currentVertex.x, currentVertex.y, // vertex pos - -flip * prevNormal.y, flip * prevNormal.x, // extrude normal - 0, 1, distance); // texture normal + e3 = vertexBuffer->add(currentVertex.x, currentVertex.y, // vertex pos + flip * (prevNormal.x + prevNormal.y), flip * (-prevNormal.x + prevNormal.y), // extrude normal + 0, 0, distance) - vertex_start; // texture normal - // Degenerate triangle - if (join == JoinType::Round || join == JoinType::Butt) { - buffer->addDegenerate(); - } + if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3); + e1 = e2; e2 = e3; - if (join == JoinType::Round) prevVertex = Coordinate::null(); + // Add second vertex + e3 = vertexBuffer->add(currentVertex.x, currentVertex.y, // vertex pos + flip * (prevNormal.x - prevNormal.y), flip * (prevNormal.x + prevNormal.y), // extrude normal + 0, 1, distance) - vertex_start; // texture normal - prevNormal = { -nextNormal.x, -nextNormal.y }; - flip = 1; + if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3); + e1 = e2; e2 = e3; } - // Add a cap. - if (!prevVertex && (beginCap == CapType::Round || beginCap == CapType::Square || (roundJoin && join == JoinType::Round))) { - int8_t tex = beginCap == CapType::Round || roundJoin ? 1 : 0; - + // Add offset square end cap. + else if (!nextVertex && endCap == CapType::Square) { // Add first vertex - buffer->add(currentVertex.x, currentVertex.y, // vertex pos - flip * (prevNormal.x + prevNormal.y), flip * (-prevNormal.x + prevNormal.y), // extrude normal - tex, 0, distance); // texture normal + e3 = vertexBuffer->add(currentVertex.x, currentVertex.y, // vertex pos + nextNormal.x - flip * nextNormal.y, flip * nextNormal.x + nextNormal.y, // extrude normal + 0, 0, distance) - vertex_start; // texture normal + + if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3); + e1 = e2; e2 = e3; // Add second vertex - buffer->add(currentVertex.x, currentVertex.y, // vertex pos - flip * (prevNormal.x - prevNormal.y), flip * (prevNormal.x + prevNormal.y), // extrude normal - tex, 1, distance); // texture normal - } + e3 = vertexBuffer->add(currentVertex.x, currentVertex.y, // vertex pos + nextNormal.x + flip * nextNormal.y, -flip * nextNormal.x + nextNormal.y, // extrude normal + 0, 1, distance) - vertex_start; // texture normal - if (roundJoin) { - // ROUND JOIN - // Add first vertex - buffer->add(currentVertex.x, currentVertex.y, // vertex pos - -flip * nextNormal.y, flip * nextNormal.x, // extrude normal - 0, 0, distance); // texture normal + if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3); + e1 = e2; e2 = e3; + } - // Add second vertex - buffer->add(currentVertex.x, currentVertex.y, // vertex pos - flip * nextNormal.y, -flip * nextNormal.x, // extrude normal - 0, 1, distance); // texture normal - } else if ((nextVertex || endCap != CapType::Square) && (prevVertex || beginCap != CapType::Square)) { + else + if (currentJoin == JoinType::Miter) { // MITER JOIN if (fabs(joinAngularity) < 0.01) { // The two normals are almost parallel. @@ -226,58 +211,126 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) { // bevel join. joinNormal.x = (prevNormal.x - nextNormal.x) / joinAngularity; joinNormal.y = (prevNormal.y - nextNormal.y) / joinAngularity; + } + + if (roundness > miterLimit) { flip = -flip; } // Add first vertex - buffer->add(currentVertex.x, currentVertex.y, // vertex pos - flip * joinNormal.x, flip * joinNormal.y, // extrude normal - 0, 0, distance); // texture normal + e3 = vertexBuffer->add(currentVertex.x, currentVertex.y, // vertex pos + flip * joinNormal.x, flip * joinNormal.y, // extrude normal + 0, 0, distance) - vertex_start; // texture normal + + if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3); + e1 = e2; e2 = e3; // Add second vertex - buffer->add(currentVertex.x, currentVertex.y, // vertex pos - -flip * joinNormal.x, -flip * joinNormal.y, // extrude normal - 0, 1, distance); // texture normal + e3 = vertexBuffer->add(currentVertex.x, currentVertex.y, // vertex pos + -flip * joinNormal.x, -flip * joinNormal.y, // extrude normal + 0, 1, distance) - vertex_start; // texture normal + + if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3); + e1 = e2; e2 = e3; + + if ((!prevVertex && beginCap == CapType::Round) || + (!nextVertex && endCap == CapType::Round)) { + pointElementsBuffer->add(e1); + } } - // Add the end cap, but only if this vertex is distinct from the begin - // vertex. - if (!nextVertex && (endCap == CapType::Round || endCap == CapType::Square)) { - int8_t capTex = endCap == CapType::Round ? 1 : 0; + else { + // Close up the previous line + // Add first vertex + e3 = vertexBuffer->add(currentVertex.x, currentVertex.y, // vertex pos + flip * prevNormal.y, -flip * prevNormal.x, // extrude normal + 0, 0, distance) - vertex_start; // texture normal + + if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3); + e1 = e2; e2 = e3; + + // Add second vertex. + e3 = vertexBuffer->add(currentVertex.x, currentVertex.y, // vertex pos + -flip * prevNormal.y, flip * prevNormal.x, // extrude normal + 0, 1, distance) - vertex_start; // texture normal + + if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3); + e1 = e2; e2 = e3; + + prevNormal = { -nextNormal.x, -nextNormal.y }; + flip = 1; + + + // begin/end caps + if ((!prevVertex && beginCap == CapType::Round) || + (!nextVertex && endCap == CapType::Round)) { + pointElementsBuffer->add(e1); + } + + + if (currentJoin == JoinType::Round) { + if (prevVertex && nextVertex && (!closed || i > 0)) { + pointElementsBuffer->add(e1); + } + // Reset the previous vertices so that we don't accidentally create + // any triangles. + e1 = -1; e2 = -1; e3 = -1; + } + + // Start the new quad. // Add first vertex - buffer->add(currentVertex.x, currentVertex.y, // vertex pos - nextNormal.x - flip * nextNormal.y, flip * nextNormal.x + nextNormal.y, // extrude normal - capTex, 0, distance); // texture normal + e3 = vertexBuffer->add(currentVertex.x, currentVertex.y, // vertex pos + -flip * nextNormal.y, flip * nextNormal.x, // extrude normal + 0, 0, distance) - vertex_start; // texture normal + + if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3); + e1 = e2; e2 = e3; // Add second vertex - buffer->add(currentVertex.x, currentVertex.y, // vertex pos - nextNormal.x + flip * nextNormal.y, -flip * nextNormal.x + nextNormal.y, // extrude normal - capTex, 1, distance); // texture normal + e3 = vertexBuffer->add(currentVertex.x, currentVertex.y, // vertex pos + flip * nextNormal.y, -flip * nextNormal.x, // extrude normal + 0, 1, distance) - vertex_start; // texture normal + + if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3); + e1 = e2; e2 = e3; } } - // Update the length. - length = buffer->index() - start; + // Update the lengths. + vertex_length = vertexBuffer->index() - vertex_start; + triangle_length = triangleElementsBuffer->index() - triangle_elements_start; + point_length = pointElementsBuffer->index() - point_elements_start; } void LineBucket::render(Painter& painter, const std::string& layer_name, const Tile::ID& id) { painter.renderLine(*this, layer_name, id); } -size_t LineBucket::size() const { - return length; +bool LineBucket::empty() const { + return vertex_length == 0; +} + +bool LineBucket::hasPoints() const { + return point_length > 0; } -void LineBucket::bind(LineShader& shader) { - char *vertex_index = BUFFER_OFFSET(start * 4 * sizeof(int16_t)); - array.bind(shader, *buffer, vertex_index); +void LineBucket::drawLines(LineShader& shader) { + char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer->itemSize); + char *elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer->itemSize); + lineArray.bind(shader, *vertexBuffer, *triangleElementsBuffer, vertex_index); + glDrawElements(GL_TRIANGLES, triangle_length * 3, GL_UNSIGNED_SHORT, elements_index); } -void LineBucket::drawLines() { - glDrawArrays(GL_TRIANGLE_STRIP, 0, length); +void LineBucket::drawDebugLines(LineShader& shader) { + char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer->itemSize); + lineArray.bind(shader, *vertexBuffer, *triangleElementsBuffer, vertex_index); + glDrawArrays(GL_LINE_STRIP, 0, vertex_length); } -void LineBucket::drawPoints() { - glDrawArrays(GL_POINTS, 0, length); +void LineBucket::drawPoints(LinejoinShader& shader) { + char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer->itemSize); + char *elements_index = BUFFER_OFFSET(point_elements_start * pointElementsBuffer->itemSize); + pointArray.bind(shader, *vertexBuffer, *pointElementsBuffer, vertex_index); + glDrawElements(GL_POINTS, point_length, GL_UNSIGNED_SHORT, elements_index); } diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index a00ead94fd..71e1dcfc86 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -32,6 +32,7 @@ void Painter::setup() { assert(plainShader); assert(outlineShader); assert(lineShader); + assert(linejoinShader); assert(patternShader); glEnable(GL_STENCIL_TEST); @@ -46,6 +47,7 @@ void Painter::setupShaders() { plainShader = std::make_unique<PlainShader>(); outlineShader = std::make_unique<OutlineShader>(); lineShader = std::make_unique<LineShader>(); + linejoinShader = std::make_unique<LinejoinShader>(); patternShader = std::make_unique<PatternShader>(); } @@ -213,7 +215,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons if (properties.antialias) { glUseProgram(outlineShader->program); glUniformMatrix4fv(outlineShader->u_matrix, 1, GL_FALSE, matrix.data()); - glLineWidth(2); + glLineWidth(2.0f); // This is always fixed and does not depend on the pixelRatio! if (properties.stroke_color != properties.fill_color) { // If we defined a different color for the fill outline, we are @@ -233,7 +235,6 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons // Draw the entire line glUniform2f(outlineShader->u_world, transform.fb_width, transform.fb_height); - glLineWidth(2.0f); bucket.drawVertices(*outlineShader); } @@ -286,13 +287,16 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons const LineProperties& properties = style.computed.lines[layer_name]; // Abort early. - if (!bucket.size()) return; + if (bucket.empty()) return; if (properties.hidden) return; double width = properties.width; - double offset = (properties.offset || 0) / 2; - double inset = fmax(-1, offset - width / 2 - 0.5) + 1; - double outset = offset + width / 2 + 0.5; + double offset = properties.offset / 2; + + // These are the radii of the line. We are limiting it to 16, which will result + // in a point size of 64 on retina. + double inset = fmin((fmax(-1, offset - width / 2 - 0.5) + 1), 16.0f); + double outset = fmin(offset + width / 2 + 0.5, 16.0f); Color color = properties.color; color[0] *= properties.opacity; @@ -300,10 +304,19 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons color[2] *= properties.opacity; color[3] *= properties.opacity; + // 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) { + glUseProgram(linejoinShader->program); + glUniformMatrix4fv(linejoinShader->u_matrix, 1, GL_FALSE, matrix.data()); + glUniform4fv(linejoinShader->u_color, 1, color.data()); + glUniform2f(linejoinShader->u_world, transform.fb_width / 2, transform.fb_height / 2); + glUniform2f(linejoinShader->u_linewidth, (outset - 0.25) * transform.pixelRatio, (inset - 0.25) * transform.pixelRatio); + glPointSize(ceil(transform.pixelRatio * outset * 2.0)); + bucket.drawPoints(*linejoinShader); + } + // var imagePos = properties.image && imageSprite.getPosition(properties.image); - // var shader; bool imagePos = false; - if (imagePos) { // var factor = 8 / Math.pow(2, painter.transform.zoom - params.z); @@ -321,38 +334,17 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons glUseProgram(lineShader->program); glUniformMatrix4fv(lineShader->u_matrix, 1, GL_FALSE, matrix.data()); glUniformMatrix4fv(lineShader->u_exmatrix, 1, GL_FALSE, exMatrix.data()); - // glUniform2fv(painter.lineShader.u_dasharray, properties.dasharray || [1, -1]); - glUniform2f(lineShader->u_dasharray, 1, -1); - // TODO: Move this to transform? const double tilePixelRatio = transform.getScale() / (1 << transform.getIntegerZoom()) / 8; + glUniform2f(lineShader->u_dasharray, 1, -1); glUniform2f(lineShader->u_linewidth, outset, inset); glUniform1f(lineShader->u_ratio, tilePixelRatio); - glUniform1f(lineShader->u_gamma, transform.pixelRatio); - - // const Color& color = properties.color; - // if (!params.antialiasing) { - // color[3] = Infinity; - // glUniform4fv(lineShader->u_color, color); - // } else { glUniform4fv(lineShader->u_color, 1, color.data()); - // } - - - glUniform1f(lineShader->u_point, 0); - bucket.bind(*lineShader); - bucket.drawLines(); - - if (bucket.geometry.join == JoinType::Round) { - glUniform1f(lineShader->u_point, 1); - bucket.drawPoints(); - } + glUniform1f(lineShader->u_debug, 0); + bucket.drawLines(*lineShader); } - - // statistics - // stats.lines += count; } void Painter::renderDebug(const Tile::Ptr& tile) { @@ -364,16 +356,16 @@ void Painter::renderDebug(const Tile::Ptr& tile) { // draw tile outline tileBorderArray.bind(*plainShader, tileBorderBuffer, BUFFER_OFFSET(0)); glUniform4f(plainShader->u_color, 1.0f, 0.0f, 0.0f, 1.0f); - glLineWidth(4.0f); + glLineWidth(4.0f * transform.pixelRatio); glDrawArrays(GL_LINE_STRIP, 0, tileBorderBuffer.index()); // draw debug info tile->debugFontArray.bind(*plainShader, tile->debugFontBuffer, BUFFER_OFFSET(0)); glUniform4f(plainShader->u_color, 1.0f, 1.0f, 1.0f, 1.0f); - glLineWidth(4.0f); + glLineWidth(4.0f * transform.pixelRatio); glDrawArrays(GL_LINES, 0, tile->debugFontBuffer.index()); glUniform4f(plainShader->u_color, 0.0f, 0.0f, 0.0f, 1.0f); - glLineWidth(2.0f); + glLineWidth(2.0f * transform.pixelRatio); glDrawArrays(GL_LINES, 0, tile->debugFontBuffer.index()); // Revert blending mode to blend to the back. diff --git a/src/renderer/shader-line.cpp b/src/renderer/shader-line.cpp index feed1626e5..667af4fe12 100644 --- a/src/renderer/shader-line.cpp +++ b/src/renderer/shader-line.cpp @@ -24,20 +24,18 @@ LineShader::LineShader() u_exmatrix = glGetUniformLocation(program, "u_exmatrix"); u_linewidth = glGetUniformLocation(program, "u_linewidth"); u_color = glGetUniformLocation(program, "u_color"); - u_debug = glGetUniformLocation(program, "u_debug"); u_ratio = glGetUniformLocation(program, "u_ratio"); u_dasharray = glGetUniformLocation(program, "u_dasharray"); - u_point = glGetUniformLocation(program, "u_point"); - u_gamma = glGetUniformLocation(program, "u_gamma"); + u_debug = glGetUniformLocation(program, "u_debug"); } void LineShader::bind(char *offset) { glEnableVertexAttribArray(a_pos); glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 8, offset); - glEnableVertexAttribArray(a_extrude); - glVertexAttribPointer(a_extrude, 2, GL_BYTE, false, 8, offset + 6); - glEnableVertexAttribArray(a_linesofar); glVertexAttribPointer(a_linesofar, 1, GL_SHORT, false, 8, offset + 4); + + glEnableVertexAttribArray(a_extrude); + glVertexAttribPointer(a_extrude, 2, GL_BYTE, false, 8, offset + 6); }
\ No newline at end of file diff --git a/src/renderer/shader-linejoin.cpp b/src/renderer/shader-linejoin.cpp new file mode 100644 index 0000000000..5d9fa13ecb --- /dev/null +++ b/src/renderer/shader-linejoin.cpp @@ -0,0 +1,31 @@ +#include <llmr/renderer/shader-linejoin.hpp> +#include <llmr/shader/shaders.hpp> +#include <llmr/platform/gl.hpp> + +#include <cstdio> + +using namespace llmr; + +LinejoinShader::LinejoinShader() + : Shader( + shaders[LINEJOIN_SHADER].vertex, + shaders[LINEJOIN_SHADER].fragment + ) { + if (!valid) { + fprintf(stderr, "invalid line shader\n"); + return; + } + + a_pos = glGetAttribLocation(program, "a_pos"); + + u_matrix = glGetUniformLocation(program, "u_matrix"); + u_world = glGetUniformLocation(program, "u_world"); + u_linewidth = glGetUniformLocation(program, "u_linewidth"); + u_color = glGetUniformLocation(program, "u_color"); +} + +void LinejoinShader::bind(char *offset) { + glEnableVertexAttribArray(a_pos); + // Note: We're referring to the vertices in a line array, which are 8 bytes long! + glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 8, offset); +} diff --git a/src/shader/line.fragment.glsl b/src/shader/line.fragment.glsl index 8064e5c733..6cef488633 100644 --- a/src/shader/line.fragment.glsl +++ b/src/shader/line.fragment.glsl @@ -1,9 +1,6 @@ -// shared uniform float u_debug; uniform vec2 u_linewidth; uniform vec4 u_color; -uniform float u_point; -uniform float u_gamma; uniform vec2 u_dasharray; @@ -12,23 +9,21 @@ varying float v_linesofar; void main() { // Calculate the distance of the pixel from the line in pixels. - float dist = length(v_normal) * (1.0 - u_point) + u_point * length(gl_PointCoord * 2.0 - 1.0); - - dist *= u_linewidth.s; + float dist = length(v_normal) * u_linewidth.s; // 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) * u_gamma, 0.0, 1.0); + float alpha = clamp(min(dist - (u_linewidth.t - 1.0), u_linewidth.s - dist), 0.0, 1.0); // Calculate the antialiasing fade factor based on distance to the dash. // Only affects alpha when line is dashed float pos = mod(v_linesofar, u_dasharray.x + u_dasharray.y); alpha *= max(step(0.0, -u_dasharray.y), clamp(min(pos, u_dasharray.x - pos), 0.0, 1.0)); - gl_FragColor = u_color * alpha; - if (u_debug > 0.0) { - gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + gl_FragColor = u_color; + } else { + gl_FragColor = u_color * alpha; } -} +}
\ No newline at end of file diff --git a/src/shader/line.vertex.glsl b/src/shader/line.vertex.glsl index 8520930b47..f70933046d 100644 --- a/src/shader/line.vertex.glsl +++ b/src/shader/line.vertex.glsl @@ -1,29 +1,26 @@ -// these are the shaders for rendering antialiased lines - // floor(127 / 2) == 63.0 // the maximum allowed miter limit is 2.0 at the moment. the extrude normal is // stored in a byte (-128..127). we scale regular normals up to length 63, but // there are also "special" normals that have a bigger length (of up to 126 in // this case). -#define scale 63.0 +// #define scale 63.0 +#define scale 0.015873016 attribute vec2 a_pos; attribute vec2 a_extrude; attribute float a_linesofar; -// matrix is for the vertex position, exmatrix is for rotating and projecting +// posmatrix is for the vertex position, exmatrix is for rotating and projecting // the extrusion vector. uniform mat4 u_matrix; uniform mat4 u_exmatrix; - uniform float u_debug; // shared uniform float u_ratio; uniform vec2 u_linewidth; uniform vec4 u_color; -uniform float u_point; varying vec2 v_normal; varying float v_linesofar; @@ -39,24 +36,18 @@ void main() { // Scale the extrusion vector down to a normal and then up by the line width // of this vertex. - vec2 extrude = a_extrude / scale; - vec2 dist = u_linewidth.s * extrude * (1.0 - u_point); - - // If the x coordinate is the maximum integer, we move the z coordinates out - // of the view plane so that the triangle gets clipped. This makes it easier - // for us to create degenerate triangle strips. - float z = step(32767.0, a_pos.x) * 2.0; - - // When drawing points, skip every other vertex - z += u_point * step(1.0, v_normal.y); + vec4 dist = vec4(u_linewidth.s * a_extrude * scale, 0.0, 0.0); // Remove the texture normal bit of the position before scaling it with the // model/view matrix. Add the extrusion vector *after* the model/view matrix // because we're extruding the line in pixel space, regardless of the current // tile's zoom level. - gl_Position = u_matrix * vec4(floor(a_pos / 2.0), 0.0, 1.0) + u_exmatrix * vec4(dist, z, 0.0); + gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0.0, 1.0) + u_exmatrix * dist; v_linesofar = a_linesofar * u_ratio; + gl_PointSize = 8.0; - gl_PointSize = 2.0 * u_linewidth.s - 1.0; -} + if (u_debug > 1.5) { + gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0.0, 1.0); + } +}
\ No newline at end of file diff --git a/src/shader/linejoin.fragment.glsl b/src/shader/linejoin.fragment.glsl new file mode 100644 index 0000000000..705a57766e --- /dev/null +++ b/src/shader/linejoin.fragment.glsl @@ -0,0 +1,14 @@ +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/shader/linejoin.vertex.glsl b/src/shader/linejoin.vertex.glsl new file mode 100644 index 0000000000..8e67af2539 --- /dev/null +++ b/src/shader/linejoin.vertex.glsl @@ -0,0 +1,12 @@ +attribute vec2 a_pos; + +uniform mat4 u_matrix; +uniform vec2 u_world; + +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_linewidth.s * 2.0; +} diff --git a/src/shader/shaders.cpp b/src/shader/shaders.cpp index 59fc34839e..3b06fbcf15 100644 --- a/src/shader/shaders.cpp +++ b/src/shader/shaders.cpp @@ -5,8 +5,12 @@ using namespace llmr; const shader_source llmr::shaders[SHADER_COUNT] = { { - "// these are the shaders for rendering antialiased lines\n\n// floor(127 / 2) == 63.0\n// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is\n// stored in a byte (-128..127). we scale regular normals up to length 63, but\n// there are also \"special\" normals that have a bigger length (of up to 126 in\n// this case).\n#define scale 63.0\n\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\n\n// matrix is for the vertex position, exmatrix is for rotating and projecting\n// the extrusion vector.\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\n\n\nuniform float u_debug;\n\n// shared\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\nuniform float u_point;\n\nvarying vec2 v_normal;\nvarying float v_linesofar;\n\nvoid main() {\n // We store the texture normals in the most insignificant bit\n // transform y so that 0 => -1 and 1 => 1\n // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap\n // y is 1 if the normal points up, and -1 if it points down\n vec2 normal = mod(a_pos, 2.0);\n normal.y = sign(normal.y - 0.5);\n v_normal = normal;\n\n // Scale the extrusion vector down to a normal and then up by the line width\n // of this vertex.\n vec2 extrude = a_extrude / scale;\n vec2 dist = u_linewidth.s * extrude * (1.0 - u_point);\n\n // If the x coordinate is the maximum integer, we move the z coordinates out\n // of the view plane so that the triangle gets clipped. This makes it easier\n // for us to create degenerate triangle strips.\n float z = step(32767.0, a_pos.x) * 2.0;\n\n // When drawing points, skip every other vertex\n z += u_point * step(1.0, v_normal.y);\n\n // Remove the texture normal bit of the position before scaling it with the\n // model/view matrix. Add the extrusion vector *after* the model/view matrix\n // because we're extruding the line in pixel space, regardless of the current\n // tile's zoom level.\n gl_Position = u_matrix * vec4(floor(a_pos / 2.0), 0.0, 1.0) + u_exmatrix * vec4(dist, z, 0.0);\n v_linesofar = a_linesofar * u_ratio;\n\n\n gl_PointSize = 2.0 * u_linewidth.s - 1.0;\n}\n", - "// shared\nuniform float u_debug;\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\nuniform float u_point;\nuniform float u_gamma;\n\nuniform vec2 u_dasharray;\n\nvarying vec2 v_normal;\nvarying float v_linesofar;\n\nvoid main() {\n // Calculate the distance of the pixel from the line in pixels.\n float dist = length(v_normal) * (1.0 - u_point) + u_point * length(gl_PointCoord * 2.0 - 1.0);\n\n dist *= u_linewidth.s;\n\n // Calculate the antialiasing fade factor. This is either when fading in\n // the line in case of an offset line (v_linewidth.t) or when fading out\n // (v_linewidth.s)\n float alpha = clamp(min(dist - (u_linewidth.t - 1.0), u_linewidth.s - dist) * u_gamma, 0.0, 1.0);\n\n // Calculate the antialiasing fade factor based on distance to the dash.\n // Only affects alpha when line is dashed\n float pos = mod(v_linesofar, u_dasharray.x + u_dasharray.y);\n alpha *= max(step(0.0, -u_dasharray.y), clamp(min(pos, u_dasharray.x - pos), 0.0, 1.0));\n\n gl_FragColor = u_color * alpha;\n\n if (u_debug > 0.0) {\n gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n }\n}\n", + "// floor(127 / 2) == 63.0\n// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is\n// stored in a byte (-128..127). we scale regular normals up to length 63, but\n// there are also \"special\" normals that have a bigger length (of up to 126 in\n// this case).\n// #define scale 63.0\n#define scale 0.015873016\n\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\n\n// posmatrix is for the vertex position, exmatrix is for rotating and projecting\n// the extrusion vector.\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\n\nuniform float u_debug;\n\n// shared\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\n\nvarying vec2 v_normal;\nvarying float v_linesofar;\n\nvoid main() {\n // We store the texture normals in the most insignificant bit\n // transform y so that 0 => -1 and 1 => 1\n // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap\n // y is 1 if the normal points up, and -1 if it points down\n vec2 normal = mod(a_pos, 2.0);\n normal.y = sign(normal.y - 0.5);\n v_normal = normal;\n\n // Scale the extrusion vector down to a normal and then up by the line width\n // of this vertex.\n vec4 dist = vec4(u_linewidth.s * a_extrude * scale, 0.0, 0.0);\n\n // Remove the texture normal bit of the position before scaling it with the\n // model/view matrix. Add the extrusion vector *after* the model/view matrix\n // because we're extruding the line in pixel space, regardless of the current\n // tile's zoom level.\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0.0, 1.0) + u_exmatrix * dist;\n v_linesofar = a_linesofar * u_ratio;\n\n gl_PointSize = 8.0;\n\n if (u_debug > 1.5) {\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0.0, 1.0);\n }\n}", + "uniform float u_debug;\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\n\nuniform vec2 u_dasharray;\n\nvarying vec2 v_normal;\nvarying float v_linesofar;\n\nvoid main() {\n // Calculate the distance of the pixel from the line in pixels.\n float dist = length(v_normal) * u_linewidth.s;\n\n // Calculate the antialiasing fade factor. This is either when fading in\n // the line in case of an offset line (v_linewidth.t) or when fading out\n // (v_linewidth.s)\n float alpha = clamp(min(dist - (u_linewidth.t - 1.0), u_linewidth.s - dist), 0.0, 1.0);\n\n // Calculate the antialiasing fade factor based on distance to the dash.\n // Only affects alpha when line is dashed\n float pos = mod(v_linesofar, u_dasharray.x + u_dasharray.y);\n alpha *= max(step(0.0, -u_dasharray.y), clamp(min(pos, u_dasharray.x - pos), 0.0, 1.0));\n\n if (u_debug > 0.0) {\n gl_FragColor = u_color;\n } else {\n gl_FragColor = u_color * alpha;\n }\n}", + }, + { + "attribute vec2 a_pos;\n\nuniform mat4 u_matrix;\nuniform vec2 u_world;\n\nvarying vec2 v_pos;\n\nvoid main() {\n gl_Position = u_matrix * vec4(floor(a_pos / 2.0), 0.0, 1.0);\n v_pos = (gl_Position.xy + 1.0) * u_world;\n}\n", + "uniform vec4 u_color;\nuniform vec2 u_linewidth;\n\nvarying vec2 v_pos;\n\nvoid main() {\n float dist = length(v_pos - gl_FragCoord.xy);\n\n // Calculate the antialiasing fade factor. This is either when fading in\n // the line in case of an offset line (v_linewidth.t) or when fading out\n // (v_linewidth.s)\n float alpha = clamp(min(dist - (u_linewidth.t - 1.0), u_linewidth.s - dist), 0.0, 1.0);\n gl_FragColor = u_color * alpha;\n}\n", }, { "attribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform vec2 u_world;\n\nvarying vec2 v_pos;\n\nvoid main() {\n // If the x coordinate is the maximum integer, we move the z coordinates out\n // of the view plane so that the triangle gets clipped. This makes it easier\n // for us to create degenerate triangle strips.\n float z = step(32767.0, a_pos.x) * 2.0;\n gl_Position = u_matrix * vec4(a_pos, z, 1);\n\n v_pos = (gl_Position.xy + 1.0) / 2.0 * u_world;\n}\n", diff --git a/src/style/resources.cpp b/src/style/resources.cpp index def1933ff2..15b6aa040a 100644 --- a/src/style/resources.cpp +++ b/src/style/resources.cpp @@ -9,14 +9,14 @@ const unsigned char resources::style[] = { 111, 97, 100, 95, 108, 97, 114, 103, 101, 16, 2, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 4, 114, 111, 97, 100, 42, 5, 99, 108, 97, 115, 115, 50, 10, 10, 8, 109, 111, 116, 111, 114, 119, 97, 121, 50, 6, 10, - 4, 109, 97, 105, 110, 56, 1, 64, 2, 10, 52, 10, 12, 114, 111, 97, + 4, 109, 97, 105, 110, 56, 1, 64, 3, 10, 52, 10, 12, 114, 111, 97, 100, 95, 114, 101, 103, 117, 108, 97, 114, 16, 2, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 4, 114, 111, 97, 100, 42, 5, 99, 108, 97, 115, - 115, 50, 8, 10, 6, 115, 116, 114, 101, 101, 116, 56, 1, 64, 2, 10, + 115, 50, 8, 10, 6, 115, 116, 114, 101, 101, 116, 56, 1, 64, 3, 10, 60, 10, 12, 114, 111, 97, 100, 95, 108, 105, 109, 105, 116, 101, 100, 16, 2, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 4, 114, 111, 97, 100, 42, 5, 99, 108, 97, 115, 115, 50, 16, 10, 14, 115, 116, 114, 101, 101, - 116, 95, 108, 105, 109, 105, 116, 101, 100, 56, 1, 64, 2, 10, 41, 10, + 116, 95, 108, 105, 109, 105, 116, 101, 100, 56, 1, 64, 3, 10, 41, 10, 4, 112, 97, 114, 107, 16, 1, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 7, 108, 97, 110, 100, 117, 115, 101, 42, 5, 99, 108, 97, 115, 115, 50, 6, 10, 4, 112, 97, 114, 107, 10, 41, 10, 4, 119, 111, 111, 100, |