From 71c31cee2499d44fcd590136d15c5da7fbfb65ec Mon Sep 17 00:00:00 2001 From: Lauren Budorick Date: Fri, 25 Jul 2014 18:17:37 -0700 Subject: linepattern in progress --- include/mbgl/renderer/line_bucket.hpp | 4 +- include/mbgl/renderer/painter.hpp | 2 + include/mbgl/shader/linepattern_shader.hpp | 59 ++++++++++++++ src/renderer/line_bucket.cpp | 14 ++++ src/renderer/painter.cpp | 2 + src/renderer/painter_line.cpp | 57 +++++++++++--- src/shader/linepattern.fragment.glsl | 34 ++++++++ src/shader/linepattern.vertex.glsl | 53 +++++++++++++ src/shader/linepattern_shader.cpp | 121 +++++++++++++++++++++++++++++ 9 files changed, 333 insertions(+), 13 deletions(-) create mode 100644 include/mbgl/shader/linepattern_shader.hpp create mode 100644 src/shader/linepattern.fragment.glsl create mode 100644 src/shader/linepattern.vertex.glsl create mode 100644 src/shader/linepattern_shader.cpp diff --git a/include/mbgl/renderer/line_bucket.hpp b/include/mbgl/renderer/line_bucket.hpp index c7e375a0a1..8babb734ed 100644 --- a/include/mbgl/renderer/line_bucket.hpp +++ b/include/mbgl/renderer/line_bucket.hpp @@ -17,10 +17,11 @@ class LineVertexBuffer; class TriangleElementsBuffer; class LineShader; class LinejoinShader; +class LinepatternShader; struct pbf; class LineBucket : public Bucket { - typedef ElementGroup<1> triangle_group_type; + typedef ElementGroup<2> triangle_group_type; typedef ElementGroup<1> point_group_type; public: @@ -38,6 +39,7 @@ public: bool hasPoints() const; void drawLines(LineShader& shader); + void drawLinePatterns(LinepatternShader& shader); void drawPoints(LinejoinShader& shader); public: diff --git a/include/mbgl/renderer/painter.hpp b/include/mbgl/renderer/painter.hpp index a8fe62b550..534323dd5d 100644 --- a/include/mbgl/renderer/painter.hpp +++ b/include/mbgl/renderer/painter.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -169,6 +170,7 @@ public: std::unique_ptr outlineShader; std::unique_ptr lineShader; std::unique_ptr linejoinShader; + std::unique_ptr linepatternShader; std::unique_ptr patternShader; std::unique_ptr iconShader; std::unique_ptr rasterShader; diff --git a/include/mbgl/shader/linepattern_shader.hpp b/include/mbgl/shader/linepattern_shader.hpp new file mode 100644 index 0000000000..7d98b295a8 --- /dev/null +++ b/include/mbgl/shader/linepattern_shader.hpp @@ -0,0 +1,59 @@ +#ifndef MBGL_SHADER_SHADER_LINEPATTERN +#define MBGL_SHADER_SHADER_LINEPATTERN + +#include + +namespace mbgl { + +class LinepatternShader : public Shader { +public: + LinepatternShader(); + + void bind(char *offset); + + void setExtrudeMatrix(const std::array& exmatrix); + void setLineWidth(const std::array& linewidth); + void setRatio(float ratio); + void setDebug(float debug); + void setPatternSize(const std::array& new_pattern_size); + void setPatternTopLeft(const std::array& new_pattern_tl); + void setPatternBottomRight(const std::array& new_pattern_br); + void setOffset(const std::array& offset); + void setGamma(float new_gamma); + void setFade(float new_fade); + +private: + int32_t a_pos = -1; + int32_t a_extrude = -1; + int32_t a_linesofar = -1; + + std::array exmatrix = {{}}; + int32_t u_exmatrix = -1; + + std::array linewidth = {{}}; + int32_t u_linewidth = -1; + + float ratio = 0; + int32_t u_ratio = -1; + + std::array pattern_size = {{}}; + int32_t u_pattern_size = -1; + + std::array pattern_tl = {{}}; + int32_t u_pattern_tl = -1; + + std::array pattern_br = {{}}; + int32_t u_pattern_br = -1; + + std::array offset = {{}}; + int32_t u_offset = -1; + + float gamma = 0.0f; + int32_t u_gamma = -1; + + float fade = 0; + int32_t u_fade = -1; +}; +} + +#endif diff --git a/src/renderer/line_bucket.cpp b/src/renderer/line_bucket.cpp index e089d7f61b..2e89a7c35d 100644 --- a/src/renderer/line_bucket.cpp +++ b/src/renderer/line_bucket.cpp @@ -374,6 +374,20 @@ void LineBucket::drawLines(LineShader& shader) { } } +void LineBucket::drawLinePatterns(LinepatternShader& shader) { + char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); + char *elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize); + for (triangle_group_type& group : triangleGroups) { + if (!group.elements_length) { + continue; + } + group.array[1].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index); + glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index); + vertex_index += group.vertex_length * vertexBuffer.itemSize; + elements_index += group.elements_length * triangleElementsBuffer.itemSize; + } +} + void LineBucket::drawPoints(LinejoinShader& shader) { char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); char *elements_index = BUFFER_OFFSET(point_elements_start * pointElementsBuffer.itemSize); diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 2a3d45c9ed..938bd5bd84 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -41,6 +41,7 @@ void Painter::setup() { assert(outlineShader); assert(lineShader); assert(linejoinShader); + assert(linepatternShader); assert(patternShader); assert(rasterShader); assert(textShader); @@ -70,6 +71,7 @@ void Painter::setupShaders() { if (!outlineShader) outlineShader = std::make_unique(); if (!lineShader) lineShader = std::make_unique(); if (!linejoinShader) linejoinShader = std::make_unique(); + if (!linepatternShader) linepatternShader = std::make_unique(); if (!patternShader) patternShader = std::make_unique(); if (!iconShader) iconShader = std::make_unique(); if (!rasterShader) rasterShader = std::make_unique(); diff --git a/src/renderer/painter_line.cpp b/src/renderer/painter_line.cpp index ad0778fc0b..df2fb88193 100644 --- a/src/renderer/painter_line.cpp +++ b/src/renderer/painter_line.cpp @@ -1,6 +1,9 @@ #include #include +#include #include +#include +#include #include using namespace mbgl; @@ -60,20 +63,50 @@ void Painter::renderLine(LineBucket& bucket, std::shared_ptr layer_d 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); + const std::shared_ptr &sprite = map.getSprite(); + if (properties.image.size() && sprite) { + SpriteAtlas &spriteAtlas = *map.getSpriteAtlas(); + Rect imagePos = spriteAtlas.getImage(properties.image, *sprite); + + float factor = 8.0 / std::pow(2, map.getState().getIntegerZoom() - id.z); + + float fade = std::fmod(map.getState().getZoom(), 1.0); - // imageSprite.bind(gl, true); + std::array imageSize = {{ + imagePos.w * factor, + imagePos.h * factor + } + }; - // //factor = Math.pow(2, 4 - painter.transform.zoom + params.z); - // gl.switchShader(painter.linepatternShader, painter.translatedMatrix || painter.posMatrix, painter.extrudeMatrix); - // 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); + std::array offset = {{ + (float)std::fmod(id.x * 4096, imageSize[0]), + (float)std::fmod(id.y * 4096, imageSize[1]) + } + }; + useProgram(linepatternShader->program); + linepatternShader->setMatrix(vtxMatrix); + linepatternShader->setExtrudeMatrix(extrudeMatrix); + lineShader->setDashArray({{ dash_length, dash_gap }}); + linepatternShader->setLineWidth({{ outset, inset }}); + linepatternShader->setRatio(map.getState().getPixelRatio()); + + linepatternShader->setPatternSize(imageSize); + linepatternShader->setPatternTopLeft({{ + float(imagePos.x) / spriteAtlas.getWidth(), + float(imagePos.y) / spriteAtlas.getHeight(), + }}); + linepatternShader->setPatternBottomRight({{ + float(imagePos.x + imagePos.w) / spriteAtlas.getWidth(), + float(imagePos.y + imagePos.h) / spriteAtlas.getHeight(), + }}); + linepatternShader->setOffset(offset); + linepatternShader->setGamma(map.getState().getPixelRatio()); + linepatternShader->setFade(fade); + + spriteAtlas.bind(true); + glDepthRange(strata + strata_epsilon, 1.0f); // may or may not matter + + bucket.drawLinePatterns(*linepatternShader); } else { useProgram(lineShader->program); diff --git a/src/shader/linepattern.fragment.glsl b/src/shader/linepattern.fragment.glsl new file mode 100644 index 0000000000..9d48adc5d4 --- /dev/null +++ b/src/shader/linepattern.fragment.glsl @@ -0,0 +1,34 @@ +uniform vec2 u_linewidth; +uniform float u_gamma; +uniform float u_fade; + +uniform vec2 u_pattern_size; +uniform vec2 u_pattern_tl; +uniform vec2 u_pattern_br; + +uniform sampler2D u_image; + +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) * length(gl_PointCoord * 2.0 - 1.0); + + // 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 x = mod(v_linesofar / u_pattern_size.x, 1.0); + float y = 0.5 + (v_normal.y * u_linewidth.s / u_pattern_size.y); + vec2 pos = mix(u_pattern_tl, u_pattern_br, vec2(x, y)); + float x2 = mod(x * 2.0, 1.0); + vec2 pos2 = mix(u_pattern_tl, u_pattern_br, vec2(x2, y)); + + vec4 color = texture2D(u_image, pos) * (1.0 - u_fade) + u_fade * texture2D(u_image, pos2); + + color.rgb *= color.a; + + gl_FragColor = color * alpha; +} diff --git a/src/shader/linepattern.vertex.glsl b/src/shader/linepattern.vertex.glsl new file mode 100644 index 0000000000..faf284c90a --- /dev/null +++ b/src/shader/linepattern.vertex.glsl @@ -0,0 +1,53 @@ +// 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; + +// posmatrix is for the vertex position, exmatrix is for rotating and projecting +// the extrusion vector. +uniform mat4 u_matrix; +uniform mat4 u_exmatrix; + +// shared +uniform float u_ratio; +uniform vec2 u_linewidth; +uniform vec4 u_color; + +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; + vec4 dist = vec4(u_linewidth.s * extrude, 0.0, 0.0); + + // 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); + + z += 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 * dist; + v_linesofar = a_linesofar; // * u_ratio; +} diff --git a/src/shader/linepattern_shader.cpp b/src/shader/linepattern_shader.cpp new file mode 100644 index 0000000000..ec235f648e --- /dev/null +++ b/src/shader/linepattern_shader.cpp @@ -0,0 +1,121 @@ +#include +#include +#include +#include + +#include + +using namespace mbgl; + +LinepatternShader::LinepatternShader() + : Shader( + "linepattern", + shaders[LINEPATTERN_SHADER].vertex, + shaders[LINEPATTERN_SHADER].fragment + ) { + if (!valid) { + fprintf(stderr, "invalid line pattern shader\n"); + return; + } + + a_pos = glGetAttribLocation(program, "a_pos"); + a_extrude = glGetAttribLocation(program, "a_extrude"); + a_linesofar = glGetAttribLocation(program, "a_linesofar"); + + u_matrix = glGetUniformLocation(program, "u_matrix"); + u_exmatrix = glGetUniformLocation(program, "u_exmatrix"); + u_linewidth = glGetUniformLocation(program, "u_linewidth"); + u_ratio = glGetUniformLocation(program, "u_ratio"); + u_pattern_size = glGetUniformLocation(program, "u_pattern_size"); + + u_pattern_tl = glGetUniformLocation(program, "u_pattern_tl"); + u_pattern_br = glGetUniformLocation(program, "u_pattern_br"); + u_offset = glGetUniformLocation(program, "u_offset"); + u_gamma = glGetUniformLocation(program, "u_gamma"); + u_fade = glGetUniformLocation(program, "u_fade"); + + //fprintf(stderr, "LinepatternShader:\n"); + //fprintf(stderr, " - u_matrix: %d\n", u_matrix); + //fprintf(stderr, " - u_exmatrix: %d\n", u_exmatrix); + //fprintf(stderr, " - u_linewidth: %d\n", u_linewidth); + //fprintf(stderr, " - u_ratio: %d\n", u_ratio); + //fprintf(stderr, " - u_pattern_size: %d\n", u_pattern_size); + //fprintf(stderr, " - u_pattern_tl: %d\n", u_pattern_tl); + //fprintf(stderr, " - u_pattern_br: %d\n", u_pattern_br); + //fprintf(stderr, " - u_offset: %d\n", u_offset); + //fprintf(stderr, " - u_gamma: %d\n", u_gamma); +} + +void LinepatternShader::bind(char *offset) { + glEnableVertexAttribArray(a_pos); + glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 8, offset + 0); + + glEnableVertexAttribArray(a_extrude); + glVertexAttribPointer(a_extrude, 2, GL_BYTE, false, 8, offset + 4); + + glEnableVertexAttribArray(a_linesofar); + glVertexAttribPointer(a_linesofar, 1, GL_SHORT, false, 8, offset + 6); +} + +void LinepatternShader::setExtrudeMatrix(const std::array& new_exmatrix) { + if (exmatrix != new_exmatrix) { + glUniformMatrix4fv(u_exmatrix, 1, GL_FALSE, new_exmatrix.data()); + exmatrix = new_exmatrix; + } +} + +void LinepatternShader::setPatternSize(const std::array& new_pattern_size) { + if (pattern_size != new_pattern_size) { + glUniform2fv(u_pattern_size, 1, new_pattern_size.data()); + pattern_size = new_pattern_size; + } +} + +void LinepatternShader::setLineWidth(const std::array& new_linewidth) { + if (linewidth != new_linewidth) { + glUniform2fv(u_linewidth, 1, new_linewidth.data()); + linewidth = new_linewidth; + } +} + +void LinepatternShader::setRatio(float new_ratio) { + if (ratio != new_ratio) { + glUniform1f(u_ratio, new_ratio); + ratio = new_ratio; + } +} + +void LinepatternShader::setPatternTopLeft(const std::array& new_pattern_tl) { + if (pattern_tl != new_pattern_tl) { + glUniform2fv(u_pattern_tl, 1, new_pattern_tl.data()); + pattern_tl = new_pattern_tl; + } +} + +void LinepatternShader::setPatternBottomRight(const std::array& new_pattern_br) { + if (pattern_br != new_pattern_br) { + glUniform2fv(u_pattern_br, 1, new_pattern_br.data()); + pattern_br = new_pattern_br; + } +} + +void LinepatternShader::setOffset(const std::array& new_offset) { + if (offset != new_offset) { + glUniform2fv(u_offset, 1, new_offset.data()); + offset = new_offset; + } +} + +void LinepatternShader::setGamma(float new_gamma) { + if (gamma != new_gamma) { + glUniform1f(u_gamma, new_gamma); + gamma = new_gamma; + } +} + +void LinepatternShader::setFade(float new_fade) { + if (fade != new_fade) { + glUniform1f(u_fade, new_fade); + fade = new_fade; + } +}; -- cgit v1.2.1