From f5846e1ebbfa1000f03695d57354d63913351214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 13 Feb 2014 15:32:25 +0100 Subject: [PATCH] change line_strip drawing for outlines to indexed lines --- include/llmr/geometry/elements_buffer.hpp | 11 +++ include/llmr/map/tile.hpp | 3 + include/llmr/renderer/fill_bucket.hpp | 19 ++-- include/llmr/renderer/line_bucket.hpp | 4 +- src/geometry/elements_buffer.cpp | 6 ++ src/map/tile.cpp | 3 +- src/renderer/fill_bucket.cpp | 101 ++++++++++++---------- src/renderer/line_bucket.cpp | 10 +-- src/renderer/painter.cpp | 2 +- 9 files changed, 97 insertions(+), 62 deletions(-) diff --git a/include/llmr/geometry/elements_buffer.hpp b/include/llmr/geometry/elements_buffer.hpp index 7a7ce6b12..684b3acd3 100644 --- a/include/llmr/geometry/elements_buffer.hpp +++ b/include/llmr/geometry/elements_buffer.hpp @@ -31,6 +31,17 @@ public: void add(element_type a, element_type b, element_type c); }; + +class LineElementsBuffer : public Buffer< + 4, // bytes per triangle (2 * unsigned short == 6 bytes) + GL_ELEMENT_ARRAY_BUFFER +> { +public: + typedef uint16_t element_type; + + void add(element_type a, element_type b); +}; + class PointElementsBuffer : public Buffer< 2, // bytes per point (1 unsigned short) GL_ELEMENT_ARRAY_BUFFER diff --git a/include/llmr/map/tile.hpp b/include/llmr/map/tile.hpp index 4b2aed888..99286a953 100644 --- a/include/llmr/map/tile.hpp +++ b/include/llmr/map/tile.hpp @@ -24,6 +24,7 @@ class VectorTileLayer; class FillVertexBuffer; class LineVertexBuffer; class TriangleElementsBuffer; +class LineElementsBuffer; class PointElementsBuffer; class PlainShader; @@ -76,7 +77,9 @@ public: std::shared_ptr fillVertexBuffer; std::shared_ptr lineVertexBuffer; + std::shared_ptr triangleElementsBuffer; + std::shared_ptr lineElementsBuffer; std::shared_ptr pointElementsBuffer; // Holds the buckets of this tile. diff --git a/include/llmr/renderer/fill_bucket.hpp b/include/llmr/renderer/fill_bucket.hpp index 917b23a7a..86188e4c7 100644 --- a/include/llmr/renderer/fill_bucket.hpp +++ b/include/llmr/renderer/fill_bucket.hpp @@ -18,6 +18,7 @@ namespace llmr { class Style; class FillVertexBuffer; class TriangleElementsBuffer; +class LineElementsBuffer; class BucketDescription; class OutlineShader; class PlainShader; @@ -25,17 +26,19 @@ struct Coordinate; struct pbf; class FillBucket : public Bucket { - typedef ElementGroup group_type; + typedef ElementGroup triangle_group_type; + typedef ElementGroup line_group_type; public: FillBucket(const std::shared_ptr& vertexBuffer, - const std::shared_ptr& elementsBuffer, + const std::shared_ptr& triangleElementsBuffer, + const std::shared_ptr& lineElementsBuffer, 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& line); - uint32_t size() const; + bool empty() const; void drawElements(PlainShader& shader); void drawVertices(OutlineShader& shader); @@ -45,14 +48,16 @@ public: private: std::shared_ptr vertexBuffer; - std::shared_ptr elementsBuffer; + std::shared_ptr triangleElementsBuffer; + std::shared_ptr lineElementsBuffer; // hold information on where the vertices are located in the FillBuffer const uint32_t vertex_start; - const uint32_t elements_start; - uint32_t length; + const uint32_t triangle_elements_start; + const uint32_t line_elements_start; VertexArrayObject array; - std::vector groups; + std::vector triangleGroups; + std::vector lineGroups; }; } diff --git a/include/llmr/renderer/line_bucket.hpp b/include/llmr/renderer/line_bucket.hpp index 65b07c78d..6ec9d960d 100644 --- a/include/llmr/renderer/line_bucket.hpp +++ b/include/llmr/renderer/line_bucket.hpp @@ -19,7 +19,7 @@ struct Coordinate; struct pbf; class LineBucket : public Bucket { - typedef ElementGroup line_group_type; + typedef ElementGroup triangle_group_type; typedef ElementGroup point_group_type; public: LineBucket(const std::shared_ptr& vertexBuffer, @@ -51,7 +51,7 @@ private: const uint32_t triangle_elements_start; const uint32_t point_elements_start; - std::vector lineGroups; + std::vector triangleGroups; std::vector pointGroups; }; diff --git a/src/geometry/elements_buffer.cpp b/src/geometry/elements_buffer.cpp index ea4c43644..71a3a12b1 100644 --- a/src/geometry/elements_buffer.cpp +++ b/src/geometry/elements_buffer.cpp @@ -9,6 +9,12 @@ void TriangleElementsBuffer::add(element_type a, element_type b, element_type c) elements[2] = c; } +void LineElementsBuffer::add(element_type a, element_type b) { + element_type *elements = static_cast(addElement()); + elements[0] = a; + elements[1] = b; +} + void PointElementsBuffer::add(element_type a) { uint16_t *data = static_cast(addElement()); data[0] = a; diff --git a/src/map/tile.cpp b/src/map/tile.cpp index 27ca2891e..902c2c03b 100644 --- a/src/map/tile.cpp +++ b/src/map/tile.cpp @@ -46,6 +46,7 @@ Tile::Tile(ID id, const Style& style) fillVertexBuffer(std::make_shared()), lineVertexBuffer(std::make_shared()), triangleElementsBuffer(std::make_shared()), + lineElementsBuffer(std::make_shared()), pointElementsBuffer(std::make_shared()), style(style) { @@ -169,7 +170,7 @@ std::shared_ptr Tile::createBucket(const VectorTile& tile, const BucketD } std::shared_ptr Tile::createFillBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { - std::shared_ptr bucket = std::make_shared(fillVertexBuffer, triangleElementsBuffer, bucket_desc); + std::shared_ptr bucket = std::make_shared(fillVertexBuffer, triangleElementsBuffer, lineElementsBuffer, 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 030ddbc05..d505fa807 100644 --- a/src/renderer/fill_bucket.cpp +++ b/src/renderer/fill_bucket.cpp @@ -16,14 +16,16 @@ struct geometry_too_long_exception : std::exception {}; using namespace llmr; FillBucket::FillBucket(const std::shared_ptr& vertexBuffer, - const std::shared_ptr& elementsBuffer, + const std::shared_ptr& triangleElementsBuffer, + const std::shared_ptr& lineElementsBuffer, const BucketDescription& bucket_desc) : geom_desc(bucket_desc.geometry), vertexBuffer(vertexBuffer), - elementsBuffer(elementsBuffer), + triangleElementsBuffer(triangleElementsBuffer), + lineElementsBuffer(lineElementsBuffer), vertex_start(vertexBuffer->index()), - elements_start(elementsBuffer->index()), - length(0) { + triangle_elements_start(triangleElementsBuffer->index()), + line_elements_start(lineElementsBuffer->index()) { } void FillBucket::addGeometry(pbf& geom) { @@ -49,74 +51,81 @@ void FillBucket::addGeometry(pbf& geom) { void FillBucket::addGeometry(const std::vector& line) { uint32_t vertex_start = vertexBuffer->index(); - vertexBuffer->addDegenerate(); + // vertexBuffer->addDegenerate(); for (const Coordinate& coord : line) { vertexBuffer->add(coord.x, coord.y); } - uint32_t vertex_end = vertexBuffer->index(); + size_t vertex_end = vertexBuffer->index(); - if (vertex_end - vertex_start > 65535) { + size_t vertex_count = vertex_end - vertex_start; + if (vertex_count > 65536) { throw geometry_too_long_exception(); } - FillBucket& index = *this; - if (!index.groups.size()) { - index.groups.emplace_back(); + { + if (!triangleGroups.size() || (triangleGroups.back().vertex_length + vertex_count > 65535)) { + // Move to a new group because the old one can't hold the geometry. + triangleGroups.emplace_back(); + } + + // We're generating triangle fans, so we always start with the first + // coordinate in this polygon. + triangle_group_type& group = triangleGroups.back(); + uint32_t index = group.vertex_length; + for (size_t i = 2; i < vertex_count; ++i) { + triangleElementsBuffer->add(index, index + i - 1, index + i); + } + + group.vertex_length += vertex_count; + group.elements_length += (vertex_count - 2); } - uint32_t vertex_count = vertex_end - vertex_start; - index.length += vertex_count; + { + if (!lineGroups.size() || (lineGroups.back().vertex_length + vertex_count > 65535)) { + // Move to a new group because the old one can't hold the geometry. + lineGroups.emplace_back(); + } - if (index.groups.back().vertex_length + vertex_count > 65535) { - // Move to a new group because the old one can't hold the geometry. - index.groups.emplace_back(); + // We're generating triangle fans, so we always start with the first + // coordinate in this polygon. + line_group_type& group = lineGroups.back(); + uint32_t index = group.vertex_length; + for (size_t i = 1; i < vertex_count; ++i) { + lineElementsBuffer->add(index + i - 1, index + i); + } + + group.vertex_length += vertex_count; + group.elements_length += (vertex_count - 1); } - - group_type& group = index.groups.back(); - - // We're generating triangle fans, so we always start with the first - // coordinate in this polygon. - // The first valid index that is not a degenerate. - uint16_t firstIndex = group.vertex_length + 1; - - assert(firstIndex + vertex_count - 1 < 65536); - - uint32_t elements_start = elementsBuffer->index(); - - for (uint32_t i = 2; i < vertex_count; ++i) { - elementsBuffer->add(firstIndex, firstIndex + i - 1, firstIndex + i); - } - - uint32_t elements_end = elementsBuffer->index(); - uint32_t elements_count = elements_end - elements_start; - group.vertex_length += vertex_count; - group.elements_length += elements_count; - } void FillBucket::render(Painter& painter, const std::string& layer_name, const Tile::ID& id) { painter.renderFill(*this, layer_name, id); } -uint32_t FillBucket::size() const { - return length; +bool FillBucket::empty() const { + return triangleGroups.empty(); } void FillBucket::drawElements(PlainShader& shader) { char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer->itemSize); - char *elements_index = BUFFER_OFFSET(elements_start * elementsBuffer->itemSize); - for (group_type& group : groups) { - group.array.bind(shader, *vertexBuffer, *elementsBuffer, vertex_index); - glDrawElements(GL_TRIANGLES, group.elements_length * 3 - 3, GL_UNSIGNED_SHORT, elements_index); + char *elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer->itemSize); + for (triangle_group_type& group : triangleGroups) { + group.array.bind(shader, *vertexBuffer, *triangleElementsBuffer, vertex_index); + glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index); vertex_index += group.vertex_length * vertexBuffer->itemSize; - elements_index += group.elements_length * elementsBuffer->itemSize; + elements_index += group.elements_length * triangleElementsBuffer->itemSize; } } void FillBucket::drawVertices(OutlineShader& shader) { - // Draw the entire line char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer->itemSize); - array.bind(shader, *vertexBuffer, vertex_index); - glDrawArrays(GL_LINE_STRIP, 0, length); + char *elements_index = BUFFER_OFFSET(line_elements_start * lineElementsBuffer->itemSize); + for (line_group_type& group : lineGroups) { + group.array.bind(shader, *vertexBuffer, *lineElementsBuffer, vertex_index); + glDrawElements(GL_LINES, group.elements_length * 2, GL_UNSIGNED_SHORT, elements_index); + vertex_index += group.vertex_length * vertexBuffer->itemSize; + elements_index += group.elements_length * lineElementsBuffer->itemSize; + } } diff --git a/src/renderer/line_bucket.cpp b/src/renderer/line_bucket.cpp index 2a4648d7f..f24c42d5b 100644 --- a/src/renderer/line_bucket.cpp +++ b/src/renderer/line_bucket.cpp @@ -311,12 +311,12 @@ void LineBucket::addGeometry(const std::vector& vertices) { // Store the triangle/line groups. { - if (!lineGroups.size() || (lineGroups.back().vertex_length + vertex_count > 65535)) { + if (!triangleGroups.size() || (triangleGroups.back().vertex_length + vertex_count > 65535)) { // Move to a new group because the old one can't hold the geometry. - lineGroups.emplace_back(); + triangleGroups.emplace_back(); } - line_group_type& group = lineGroups.back(); + triangle_group_type& group = triangleGroups.back(); for (const TriangleElement& triangle : triangle_store) { triangleElementsBuffer->add( group.vertex_length + triangle.a, @@ -351,7 +351,7 @@ void LineBucket::render(Painter& painter, const std::string& layer_name, const T } bool LineBucket::empty() const { - return lineGroups.empty(); + return triangleGroups.empty(); } bool LineBucket::hasPoints() const { @@ -361,7 +361,7 @@ bool LineBucket::hasPoints() const { void LineBucket::drawLines(LineShader& shader) { char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer->itemSize); char *elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer->itemSize); - for (line_group_type& group : lineGroups) { + for (triangle_group_type& group : triangleGroups) { group.array.bind(shader, *vertexBuffer, *triangleElementsBuffer, vertex_index); glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index); vertex_index += group.vertex_length * vertexBuffer->itemSize; diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 88babc05e..f8a4a86cb 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -171,7 +171,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons const FillProperties& properties = style.computed.fills[layer_name]; // Abort early. - if (!bucket.size()) return; + if (bucket.empty()) return; if (properties.hidden) return; Color fill_color = properties.fill_color;