drawing lines with triangles

This commit is contained in:
Konstantin Käfer
2014-02-11 15:51:54 +01:00
parent eb9a6b7068
commit bec0ad10c4
34 changed files with 452 additions and 263 deletions

View File

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

View File

@@ -25,7 +25,7 @@ var cap_type = {
// enum
var join_type = {
butt: 1,
miter: 1,
bevel: 2,
round: 3
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -12,6 +12,7 @@ struct shader_source {
enum {
LINE_SHADER,
LINEJOIN_SHADER,
OUTLINE_SHADER,
PATTERN_SHADER,
PLAIN_SHADER,

View File

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

View File

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

View File

@@ -13,7 +13,7 @@ enum cap_type {
}
enum join_type {
butt_join = 1;
miter_join = 1;
bevel_join = 2;
round_join = 3;
}

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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;
}
// Close up the previous line for a round join
if (roundJoin && prevVertex && nextVertex) {
// 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
// Degenerate triangle
if (join == JoinType::Round || join == JoinType::Butt) {
buffer->addDegenerate();
// Switch to miter joins if the angle is very low.
if (currentJoin != JoinType::Miter) {
if (fabs(joinAngularity) < 0.5 && roundness < miterLimit) {
currentJoin = JoinType::Miter;
}
if (join == JoinType::Round) prevVertex = Coordinate::null();
prevNormal = { -nextNormal.x, -nextNormal.y };
flip = 1;
}
// 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 begin cap.
if (!prevVertex && beginCap == 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
flip * (prevNormal.x + prevNormal.y), flip * (-prevNormal.x + prevNormal.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
flip * (prevNormal.x - prevNormal.y), flip * (prevNormal.x + prevNormal.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 (roundJoin) {
// ROUND JOIN
// Add offset square end cap.
else if (!nextVertex && endCap == CapType::Square) {
// Add first vertex
buffer->add(currentVertex.x, currentVertex.y, // vertex pos
-flip * nextNormal.y, flip * nextNormal.x, // extrude normal
0, 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 * nextNormal.y, -flip * nextNormal.x, // extrude normal
0, 1, distance); // texture normal
} else if ((nextVertex || endCap != CapType::Square) && (prevVertex || beginCap != CapType::Square)) {
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 (e1 >= 0 && e2 >= 0 && e3 >= 0) triangleElementsBuffer->add(e1, e2, e3);
e1 = e2; e2 = e3;
}
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
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 * 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
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;
}
void LineBucket::bind(LineShader& shader) {
char *vertex_index = BUFFER_OFFSET(start * 4 * sizeof(int16_t));
array.bind(shader, *buffer, vertex_index);
bool LineBucket::hasPoints() const {
return point_length > 0;
}
void LineBucket::drawLines() {
glDrawArrays(GL_TRIANGLE_STRIP, 0, length);
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::drawPoints() {
glDrawArrays(GL_POINTS, 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(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);
}

View File

@@ -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;
// var imagePos = properties.image && imageSprite.getPosition(properties.image);
// var shader;
bool imagePos = false;
// 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);
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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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