buggy line support

This commit is contained in:
Konstantin Käfer
2014-01-28 18:40:17 +01:00
parent 43ab6732d9
commit e359d697fb
16 changed files with 273 additions and 29 deletions

View File

@@ -5,6 +5,7 @@
#include <llmr/util/vec.hpp>
#include <llmr/util/animation.hpp>
#include <cmath>
#include <cstdint>
#include <forward_list>
@@ -40,6 +41,7 @@ public:
// Getters
void matrixFor(float matrix[16], const vec3<int32_t>& id) const;
float getZoom() const;
int32_t getIntegerZoom() const;
double getScale() const;
double getAngle() const;
void getLonLat(double& lon, double& lat) const;
@@ -54,19 +56,22 @@ private:
public:
// logical dimensions
uint32_t width;
uint32_t height;
uint32_t width = 0;
uint32_t height = 0;
// physical (framebuffer) dimensions
uint32_t fb_width;
uint32_t fb_height;
uint32_t fb_width = 0;
uint32_t fb_height = 0;
double pixelRatio = 1;
private:
double x, y; // pixel values of the map center in the current scale
double angle;
double scale;
double x = 0, y = 0; // pixel values of the map center in the current scale
double angle = 0;
double scale = 1;
double min_scale, max_scale;
double min_scale = pow(2, 0);
double max_scale = pow(2, 20);
// tile size
const int32_t size = 512;

View File

@@ -2,6 +2,7 @@
#define LLMR_RENDERER_LINEBUCKET
#include "bucket.hpp"
#include <llmr/style/bucket_description.hpp>
#include <vector>
@@ -9,7 +10,6 @@ namespace llmr {
class Style;
class LineBuffer;
class BucketDescription;
struct Coordinate;
struct pbf;
@@ -22,10 +22,11 @@ public:
void addGeometry(pbf& data, const BucketDescription& bucket_desc);
void addGeometry(const std::vector<Coordinate>& line, const BucketDescription& bucket_desc);
private:
public:
std::shared_ptr<LineBuffer> buffer;
uint32_t start;
uint32_t length;
JoinType join;
};
}

View File

@@ -4,6 +4,7 @@
#include "shader-fill.hpp"
#include "shader-plain.hpp"
#include "shader-outline.hpp"
#include "shader-line.hpp"
#include "../map/tile.hpp"
@@ -54,12 +55,15 @@ private:
Transform& transform;
Settings& settings;
Style& style;
float matrix[16];
float exMatrix[16];
std::shared_ptr<Shader> currentShader;
std::shared_ptr<FillShader> fillShader;
std::shared_ptr<PlainShader> plainShader;
std::shared_ptr<OutlineShader> outlineShader;
std::shared_ptr<LineShader> lineShader;
uint32_t tile_stencil_buffer;
uint32_t tile_border_buffer;

View File

@@ -0,0 +1,29 @@
#ifndef LLMR_RENDERER_SHADER_LINE
#define LLMR_RENDERER_SHADER_LINE
#include "shader.hpp"
namespace llmr {
class LineShader : public Shader {
public:
LineShader();
int32_t a_pos;
int32_t a_extrude;
int32_t a_linesofar;
int32_t u_matrix;
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;
};
}
#endif

View File

@@ -12,6 +12,7 @@ struct shader_source {
enum {
FILL_SHADER,
LINE_SHADER,
OUTLINE_SHADER,
PLAIN_SHADER,
SHADER_COUNT

View File

@@ -10,6 +10,7 @@ SET(llmr_SOURCES
renderer/shader-fill.cpp
renderer/shader-plain.cpp
renderer/shader-outline.cpp
renderer/shader-line.cpp
renderer/shader.cpp
renderer/fill_bucket.cpp
renderer/line_bucket.cpp
@@ -39,6 +40,7 @@ SET(llmr_HEADERS
../include/llmr/renderer/shader-fill.hpp
../include/llmr/renderer/shader-plain.hpp
../include/llmr/renderer/shader-outline.hpp
../include/llmr/renderer/shader-line.hpp
../include/llmr/renderer/shader.hpp
../include/llmr/shader/shaders.hpp
../include/llmr/util/animation.hpp

View File

@@ -48,6 +48,7 @@ void Map::resize(uint32_t width, uint32_t height, uint32_t fb_width, uint32_t fb
transform.height = height;
transform.fb_width = fb_width;
transform.fb_height = fb_height;
transform.pixelRatio = (double)fb_width / (double)width;
update();
}

View File

@@ -1,7 +1,6 @@
#include <llmr/map/transform.hpp>
#include <llmr/util/mat4.hpp>
#include <llmr/util/math.hpp>
#include <cmath>
#include <cstdio>
using namespace llmr;
@@ -14,16 +13,7 @@ const double M2PI = 2 * M_PI;
const double A = 6378137;
Transform::Transform()
:
width(0),
height(0),
x(0),
y(0),
angle(0.0),
scale(1.0),
min_scale(pow(2, 0)),
max_scale(pow(2, 20)) {
Transform::Transform() {
setScale(scale);
setAngle(angle);
}
@@ -168,6 +158,10 @@ float Transform::getZoom() const {
return log(scale) / M_LN2;
}
int32_t Transform::getIntegerZoom() const {
return floor(log(scale) / M_LN2);
}
double Transform::getScale() const {
return scale;
}

View File

@@ -23,6 +23,8 @@ LineBucket::LineBucket(const std::shared_ptr<LineBuffer>& buffer)
}
void LineBucket::addGeometry(pbf& geom, const BucketDescription& bucket_desc) {
join = bucket_desc.join;
std::vector<Coordinate> line;
Geometry::command cmd;

View File

@@ -54,6 +54,7 @@ void Painter::setup() {
assert(fillShader);
assert(plainShader);
assert(outlineShader);
assert(lineShader);
// Set up the stencil quad we're using to generate the stencil mask.
glGenBuffers(1, &tile_stencil_buffer);
@@ -78,6 +79,7 @@ void Painter::setupShaders() {
fillShader = std::make_shared<FillShader>();
plainShader = std::make_shared<PlainShader>();
outlineShader = std::make_shared<OutlineShader>();
lineShader = std::make_shared<LineShader>();
}
void Painter::teardown() {
@@ -89,10 +91,13 @@ void Painter::changeMatrix(const Tile::Ptr& tile) {
float projMatrix[16];
mat4::ortho(projMatrix, 0, transform.width, transform.height, 0, 1, 10);
float mvMatrix[16];
transform.matrixFor(mvMatrix, tile->id);
// The position matrix.
transform.matrixFor(matrix, tile->id);
mat4::multiply(matrix, projMatrix, matrix);
mat4::multiply(matrix, projMatrix, mvMatrix);
// The extrusion matrix.
mat4::copy(exMatrix, projMatrix);
mat4::rotate_z(exMatrix, exMatrix, transform.getAngle());
}
void Painter::drawClippingMask() {
@@ -318,7 +323,73 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name) {
void Painter::renderLine(LineBucket& bucket, const std::string& layer_name) {
const LineProperties& properties = style.computed.lines[layer_name];
// TODO
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;
// var imagePos = properties.image && imageSprite.getPosition(properties.image);
// var shader;
bool imagePos = false;
if (imagePos) {
// var factor = 8 / Math.pow(2, painter.transform.zoom - params.z);
// imageSprite.bind(gl, true);
// //factor = Math.pow(2, 4 - painter.transform.zoom + params.z);
// gl.switchShader(painter.linepatternShader, painter.translatedMatrix || painter.posMatrix, painter.exMatrix);
// shader = painter.linepatternShader;
// glUniform2fv(painter.linepatternShader.u_pattern_size, [imagePos.size[0] * factor, imagePos.size[1] ]);
// glUniform2fv(painter.linepatternShader.u_pattern_tl, imagePos.tl);
// glUniform2fv(painter.linepatternShader.u_pattern_br, imagePos.br);
// glUniform1f(painter.linepatternShader.u_fade, painter.transform.z % 1.0);
} else {
switchShader(lineShader);
glUniformMatrix4fv(lineShader->u_matrix, 1, GL_FALSE, matrix);
glUniformMatrix4fv(lineShader->u_exmatrix, 1, GL_FALSE, exMatrix);
// glUniform2fv(painter.lineShader.u_dasharray, properties.dasharray || [1, -1]);
glUniform2f(lineShader->u_dasharray, 1, -1);
}
const double tilePixelRatio = transform.getScale() / (1 << transform.getIntegerZoom()) / 8;
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, properties.color.data());
// }
bucket.buffer->bind();
char *vertex_index = BUFFER_OFFSET(bucket.start * 2 * sizeof(uint16_t));
glVertexAttribPointer(lineShader->a_pos, 4, GL_SHORT, false, 8, vertex_index);
glVertexAttribPointer(lineShader->a_extrude, 2, GL_BYTE, false, 8, vertex_index + 6);
glVertexAttribPointer(lineShader->a_linesofar, 2, GL_SHORT, false, 8, vertex_index + 4);
uint32_t begin = bucket.start;
uint32_t count = bucket.length;
glUniform1f(lineShader->u_point, 0);
glDrawArrays(GL_TRIANGLE_STRIP, begin, count);
if (bucket.join == JoinType::Round) {
glUniform1f(lineShader->u_point, 1);
glDrawArrays(GL_POINTS, begin, count);
}
// statistics
// stats.lines += count;
}
void Painter::renderDebug(const Tile::Ptr& tile) {

View File

@@ -0,0 +1,33 @@
#include <llmr/renderer/shader-line.hpp>
#include <llmr/shader/shaders.hpp>
#include <llmr/platform/gl.hpp>
using namespace llmr;
LineShader::LineShader()
: Shader(
shaders[LINE_SHADER].vertex,
shaders[LINE_SHADER].fragment
) {
if (!valid) {
fprintf(stderr, "invalid line shader\n");
return;
}
a_pos = glGetAttribLocation(program, "a_pos");
attributes.emplace_front(a_pos);
a_extrude = glGetAttribLocation(program, "a_extrude");
attributes.emplace_front(a_extrude);
a_linesofar = glGetAttribLocation(program, "a_linesofar");
attributes.emplace_front(a_linesofar);
u_matrix = glGetUniformLocation(program, "u_matrix");
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");
}

View File

@@ -119,7 +119,7 @@ bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source) {
glCompileShader(*shader);
#if defined(DEBUG)
// #if defined(DEBUG)
GLint logLength;
glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
@@ -128,7 +128,7 @@ bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source) {
fprintf(stderr, "Shader compile log:\n%s", log);
free(log);
}
#endif
// #endif
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
if (status == 0) {

View File

@@ -0,0 +1,35 @@
#version 120
// 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;
varying vec2 v_normal;
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;
// 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);
// 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);
}
}

View File

@@ -0,0 +1,62 @@
// 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
attribute vec2 a_pos;
attribute vec2 a_extrude;
attribute float a_linesofar;
// matrix 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;
void main() {
// We store the texture normals in the most insignificant bit
// transform y so that 0 => -1 and 1 => 1
// In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap
// y is 1 if the normal points up, and -1 if it points down
vec2 normal = mod(a_pos, 2.0);
normal.y = sign(normal.y - 0.5);
v_normal = normal;
// 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);
// When drawing points, skip every other vertex
z += u_point * step(1.0, v_normal.y);
// 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);
v_linesofar = a_linesofar * u_ratio;
gl_PointSize = 2.0 * u_linewidth.s - 1.0;
}

View File

@@ -5,4 +5,4 @@ uniform mat4 u_matrix;
void main() {
float z = step(32767.0, a_pos.x) * 2.0;
gl_Position = u_matrix * vec4(a_pos, z, 1);
}
}

View File

@@ -8,12 +8,16 @@ const shader_source llmr::shaders[SHADER_COUNT] = {
.vertex = "attribute vec2 a_pos;\n\nuniform mat4 u_matrix;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n}\n",
.fragment = "uniform vec4 u_color;\n\nvoid main() {\n gl_FragColor = u_color;\n}\n",
},
[LINE_SHADER] = {
.vertex = "// 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);\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",
.fragment = "#version 120\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",
},
[OUTLINE_SHADER] = {
.vertex = "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",
.fragment = "uniform vec4 u_color;\n\nvarying vec2 v_pos;\n\nvoid main() {\n float dist = length(v_pos - gl_FragCoord.xy);\n float alpha = smoothstep(1.0, 0.0, dist);\n gl_FragColor = u_color * alpha;\n}\n",
},
[PLAIN_SHADER] = {
.vertex = "attribute vec2 a_pos;\n\nuniform mat4 u_matrix;\n\nvoid main() {\n float z = step(32767.0, a_pos.x) * 2.0;\n gl_Position = u_matrix * vec4(a_pos, z, 1);\n }\n",
.vertex = "attribute vec2 a_pos;\n\nuniform mat4 u_matrix;\n\nvoid main() {\n float z = step(32767.0, a_pos.x) * 2.0;\n gl_Position = u_matrix * vec4(a_pos, z, 1);\n}\n",
.fragment = "uniform vec4 u_color;\n\nvoid main() {\n gl_FragColor = u_color;\n}\n",
}
};