split line vertices into multiple buffer groups if elements overflow

This commit is contained in:
Konstantin Käfer
2014-02-11 17:34:46 +01:00
parent eb8e5fcf15
commit 662a61a396
5 changed files with 107 additions and 63 deletions

View File

@@ -59,7 +59,7 @@ protected:
}
public:
const size_t itemSize = item_size;
static const size_t itemSize = item_size;
private:
// CPU buffer

View File

@@ -18,7 +18,7 @@ public:
* normal array, while the extrude normal actually moves the vertex to create
* the acute/bevelled line join.
*/
const int8_t extrudeScale = 63;
static const int8_t extrudeScale = 63;
/*
* Add a vertex to this buffer

View File

@@ -48,11 +48,11 @@ private:
std::shared_ptr<TriangleElementsBuffer> elementsBuffer;
// hold information on where the vertices are located in the FillBuffer
uint32_t vertex_start;
uint32_t elements_start;
const uint32_t vertex_start;
const uint32_t elements_start;
uint32_t length;
VertexArrayObject<OutlineShader> array;
std::vector<ElementGroup<PlainShader>> groups;
std::vector<group_type> groups;
};
}

View File

@@ -4,6 +4,7 @@
#include "bucket.hpp"
#include <llmr/style/bucket_description.hpp>
#include <llmr/geometry/vao.hpp>
#include <llmr/geometry/elements_buffer.hpp>
#include <memory>
#include <vector>
@@ -18,6 +19,8 @@ struct Coordinate;
struct pbf;
class LineBucket : public Bucket {
typedef ElementGroup<LineShader> line_group_type;
typedef ElementGroup<LinejoinShader> point_group_type;
public:
LineBucket(const std::shared_ptr<LineVertexBuffer>& vertexBuffer,
const std::shared_ptr<TriangleElementsBuffer>& triangleElementsBuffer,
@@ -33,27 +36,23 @@ public:
bool hasPoints() const;
void drawLines(LineShader& shader);
void drawDebugLines(LineShader& shader);
void drawPoints(LinejoinShader& shader);
public:
const BucketGeometryDescription geometry;
private:
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;
const uint32_t vertex_start;
const uint32_t triangle_elements_start;
const uint32_t point_elements_start;
std::vector<line_group_type> lineGroups;
std::vector<point_group_type> pointGroups;
};
}

View File

@@ -26,14 +26,12 @@ LineBucket::LineBucket(const std::shared_ptr<LineVertexBuffer>& vertexBuffer,
const BucketDescription& bucket_desc)
: geometry(bucket_desc.geometry),
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) {
vertex_start(vertexBuffer->index()),
triangle_elements_start(triangleElementsBuffer->index()),
point_elements_start(pointElementsBuffer->index())
{
}
void LineBucket::addGeometry(pbf& geom) {
@@ -57,6 +55,13 @@ void LineBucket::addGeometry(pbf& geom) {
}
}
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 std::vector<Coordinate>& vertices) {
const JoinType join = geometry.join;
const CapType cap = geometry.cap;
@@ -98,6 +103,11 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
nextNormal = util::normal<double>(currentVertex, lastVertex);
}
size_t start_vertex = vertexBuffer->index();
std::vector<TriangleElement> triangle_store;
std::vector<PointElement> point_store;
for (size_t i = 0; i < vertices.size(); ++i) {
if (nextNormal) prevNormal = { -nextNormal.x, -nextNormal.y };
if (currentVertex) prevVertex = currentVertex;
@@ -166,17 +176,17 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
// Add first vertex
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
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3);
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// 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
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3);
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
}
@@ -185,22 +195,21 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
// Add first vertex
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
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3);
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// Add second vertex
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
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3);
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
}
else
if (currentJoin == JoinType::Miter) {
else if (currentJoin == JoinType::Miter) {
// MITER JOIN
if (fabs(joinAngularity) < 0.01) {
// The two normals are almost parallel.
@@ -220,22 +229,22 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
// Add first vertex
e3 = vertexBuffer->add(currentVertex.x, currentVertex.y, // vertex pos
flip * joinNormal.x, flip * joinNormal.y, // extrude normal
0, 0, distance) - vertex_start; // texture normal
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3);
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// Add second vertex
e3 = vertexBuffer->add(currentVertex.x, currentVertex.y, // vertex pos
-flip * joinNormal.x, -flip * joinNormal.y, // extrude normal
0, 1, distance) - vertex_start; // texture normal
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3);
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
if ((!prevVertex && beginCap == CapType::Round) ||
(!nextVertex && endCap == CapType::Round)) {
pointElementsBuffer->add(e1);
point_store.emplace_back(e1);
}
}
@@ -244,17 +253,17 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
// 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
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3);
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(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
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3);
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
prevNormal = { -nextNormal.x, -nextNormal.y };
@@ -264,13 +273,13 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
// begin/end caps
if ((!prevVertex && beginCap == CapType::Round) ||
(!nextVertex && endCap == CapType::Round)) {
pointElementsBuffer->add(e1);
point_store.emplace_back(e1);
}
if (currentJoin == JoinType::Round) {
if (prevVertex && nextVertex && (!closed || i > 0)) {
pointElementsBuffer->add(e1);
point_store.emplace_back(e1);
}
// Reset the previous vertices so that we don't accidentally create
@@ -282,25 +291,59 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
// Add first vertex
e3 = vertexBuffer->add(currentVertex.x, currentVertex.y, // vertex pos
-flip * nextNormal.y, flip * nextNormal.x, // extrude normal
0, 0, distance) - vertex_start; // texture normal
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3);
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// Add second vertex
e3 = vertexBuffer->add(currentVertex.x, currentVertex.y, // vertex pos
flip * nextNormal.y, -flip * nextNormal.x, // extrude normal
0, 1, distance) - vertex_start; // texture normal
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3);
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
}
}
// Update the lengths.
vertex_length = vertexBuffer->index() - vertex_start;
triangle_length = triangleElementsBuffer->index() - triangle_elements_start;
point_length = pointElementsBuffer->index() - point_elements_start;
size_t end_vertex = vertexBuffer->index();
size_t vertex_count = end_vertex - start_vertex;
// Store the triangle/line groups.
{
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();
}
line_group_type& group = lineGroups.back();
for (const TriangleElement& triangle : triangle_store) {
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();
}
// 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();
}
point_group_type& group = pointGroups.back();
for (PointElement point : point_store) {
pointElementsBuffer->add(group.vertex_length + point);
}
group.vertex_length += vertex_count;
group.elements_length += point_store.size();
}
}
void LineBucket::render(Painter& painter, const std::string& layer_name, const Tile::ID& id) {
@@ -308,29 +351,31 @@ void LineBucket::render(Painter& painter, const std::string& layer_name, const T
}
bool LineBucket::empty() const {
return vertex_length == 0;
return lineGroups.empty();
}
bool LineBucket::hasPoints() const {
return point_length > 0;
return !pointGroups.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);
lineArray.bind(shader, *vertexBuffer, *triangleElementsBuffer, vertex_index);
glDrawElements(GL_TRIANGLES, triangle_length * 3, GL_UNSIGNED_SHORT, elements_index);
}
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);
for (line_group_type& group : lineGroups) {
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 * 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);
pointArray.bind(shader, *vertexBuffer, *pointElementsBuffer, vertex_index);
glDrawElements(GL_POINTS, point_length, GL_UNSIGNED_SHORT, elements_index);
for (point_group_type& group : pointGroups) {
group.array.bind(shader, *vertexBuffer, *pointElementsBuffer, vertex_index);
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;
}
}