Merge pull request #1343 from mapbox/get-rid-of-gl-points

match -js line tesselation (get rid of joins drawn with GL_POINTS).
This commit is contained in:
Konstantin Käfer
2015-04-27 12:22:24 +02:00
16 changed files with 297 additions and 407 deletions

View File

@@ -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);

View File

@@ -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>

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
if (vertices.size() == 2 && closed) {
const Coordinate firstVertex = vertices.front();
const Coordinate lastVertex = vertices[len - 1];
const bool closed = firstVertex == lastVertex;
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();
const int32_t startVertex = (int32_t)vertexBuffer.index();
std::vector<TriangleElement> triangleStore;
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;
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
};
vec2<double> joinNormal = util::unit(prevNormal + nextNormal);
// 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));
/* 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;
// Switch to miter joins if the angle is very low.
if (currentJoin != JoinType::Miter) {
if (std::fabs(joinAngularity) < 0.5 && roundness < layout.miter_limit) {
// 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;
// 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 (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
}
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 (currentJoin == JoinType::Miter && miterLength > miterLimit) {
currentJoin = JoinType::Bevel;
}
if (roundness > layout.miter_limit) {
flip = -flip;
}
// 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;
// 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
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)) {
point_store.emplace_back(e1);
}
}
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
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.y, flip * prevNormal.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;
prevNormal = { -nextNormal.x, -nextNormal.y };
flip = 1;
// begin/end caps
if ((!prevVertex && beginCap == CapType::Round) ||
(!nextVertex && endCap == CapType::Round)) {
point_store.emplace_back(e1);
}
if (currentJoin == JoinType::Round) {
if (prevVertex && nextVertex && (!closed || i > 0)) {
point_store.emplace_back(e1);
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;
}
// Reset the previous vertices so that we don't accidentally create
// any triangles.
e1 = -1; e2 = -1; e3 = -1;
// 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;
}
}
}
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;
}
// 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
addCurrentVertex(currentVertex, flip, distance, joinNormal, 0, 0, false, startVertex,
triangleStore);
flip = -flip;
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
} 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;
// 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 (flip * dir > 0) {
offsetB = 0;
offsetA = offset;
} else {
offsetA = 0;
offsetB = offset;
}
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);
}
// Start next segment
if (nextVertex) {
addCurrentVertex(currentVertex, flip, distance, nextNormal, -offsetA, -offsetB,
false, startVertex, triangleStore);
}
} else if (!middleVertex && currentCap == CapType::Butt) {
if (!startOfLine) {
// Close previous segment with a butt
addCurrentVertex(currentVertex, flip, distance, prevNormal, 0, 0, false,
startVertex, triangleStore);
}
// Start next segment with a butt
if (nextVertex) {
addCurrentVertex(currentVertex, flip, distance, nextNormal, 0, 0, false,
startVertex, triangleStore);
}
} 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);
// The segment is done. Unset vertices to disconnect segments.
e1 = e2 = -1;
flip = 1;
}
// Start next segment
if (nextVertex) {
addCurrentVertex(currentVertex, flip, distance, nextNormal, -1, -1, false,
startVertex, triangleStore);
}
} 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);
// 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;
} else if (beginCap == CapType::Round) {
// Add round cap before first segment
addCurrentVertex(currentVertex, flip, distance, nextNormal, -1, -1, true,
startVertex, triangleStore);
}
// Start next segment with a butt
if (nextVertex) {
addCurrentVertex(currentVertex, flip, distance, nextNormal, 0, 0, false,
startVertex, triangleStore);
}
}
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();
}
// 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();
group.vertex_length += vertexCount;
group.elements_length += triangleStore.size();
}
}
void LineBucket::render(Painter &painter, const StyleLayer &layer_desc, const TileID &id,
const mat4 &matrix) {
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) {
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;
}
}

View File

@@ -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;
};
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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));
}

View File

@@ -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

View File

@@ -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" },
});
// -------------------------------------------------------------------------------------------------