diff --git a/include/llmr/geometry/vao.hpp b/include/llmr/geometry/vao.hpp new file mode 100644 index 000000000..6d710d831 --- /dev/null +++ b/include/llmr/geometry/vao.hpp @@ -0,0 +1,51 @@ +#ifndef LLMR_GEOMETRY_VAO +#define LLMR_GEOMETRY_VAO + +#include + +#include + +namespace llmr { + +template +class VertexArrayObject { +public: + template + void bind(Shader& shader, Buffer& buffer, char *offset) { + if (!vao) { + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + buffer.bind(); + shader.bind(offset); + + buffer_ptr = &buffer; + offset_ptr = offset; + } else if (buffer_ptr != &buffer) { + throw std::runtime_error("trying to bind VAO to another 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); + } + } + + ~VertexArrayObject() { + if (vao) { + glDeleteVertexArrays(1, &vao); + } + } + +private: + GLuint vao = 0; + + // For debug reasons, we're storing the bind information so that we can + // detect errors and report + void *buffer_ptr = NULL; + char *offset_ptr = 0; +}; + +} + +#endif diff --git a/include/llmr/map/tile.hpp b/include/llmr/map/tile.hpp index 2184af9bd..2569764cc 100644 --- a/include/llmr/map/tile.hpp +++ b/include/llmr/map/tile.hpp @@ -2,6 +2,8 @@ #define LLMR_MAP_TILE #include +#include +#include #include #include @@ -18,9 +20,9 @@ class LayerDescription; class BucketDescription; class VectorTile; class VectorTileLayer; -class DebugFontBuffer; class FillBuffer; class LineBuffer; +class PlainShader; class Tile : public std::enable_shared_from_this { public: @@ -71,7 +73,9 @@ public: state state; // Holds the actual geometries in this tile. - std::shared_ptr debugFontBuffer; + DebugFontBuffer debugFontBuffer; + VertexArrayObject debugFontArray; + std::shared_ptr fillBuffer; std::shared_ptr lineBuffer; diff --git a/include/llmr/platform/gl.hpp b/include/llmr/platform/gl.hpp index a86113d7f..4074fa081 100644 --- a/include/llmr/platform/gl.hpp +++ b/include/llmr/platform/gl.hpp @@ -8,12 +8,18 @@ #if TARGET_OS_IPHONE #include #include + #define glGenVertexArrays glGenVertexArraysOES + #define glBindVertexArray glBindVertexArrayOES + #define glDeleteVertexArrays glDeleteVertexArraysOES #elif TARGET_IPHONE_SIMULATOR #include #include #elif TARGET_OS_MAC #include #include + #define glGenVertexArrays glGenVertexArraysAPPLE + #define glBindVertexArray glBindVertexArrayAPPLE + #define glDeleteVertexArrays glDeleteVertexArraysAPPLE #else #error Unsupported Apple platform #endif diff --git a/include/llmr/renderer/fill_bucket.hpp b/include/llmr/renderer/fill_bucket.hpp index 4ab950731..e980125b1 100644 --- a/include/llmr/renderer/fill_bucket.hpp +++ b/include/llmr/renderer/fill_bucket.hpp @@ -3,15 +3,23 @@ #include "bucket.hpp" #include +#include +#include #include #include +#ifndef BUFFER_OFFSET +#define BUFFER_OFFSET(i) ((char *)NULL + (i)) +#endif + namespace llmr { class Style; class FillBuffer; class BucketDescription; +class OutlineShader; +class PlainShader; struct Coordinate; struct pbf; @@ -24,8 +32,9 @@ public: void addGeometry(pbf& data); void addGeometry(const std::vector& line); uint32_t size() const; - void drawElements(int32_t attrib); - void drawVertices(int32_t attrib); + + void drawElements(PlainShader& shader); + void drawVertices(OutlineShader& shader); public: const BucketGeometryDescription geom_desc; @@ -34,6 +43,7 @@ private: std::shared_ptr buffer; struct group { + VertexArrayObject array; uint32_t vertex_length; uint32_t elements_length; @@ -48,6 +58,7 @@ private: uint32_t vertex_start; uint32_t elements_start; uint32_t length; + VertexArrayObject array; std::vector groups; }; diff --git a/include/llmr/renderer/line_bucket.hpp b/include/llmr/renderer/line_bucket.hpp index f6caededa..7d61af15e 100644 --- a/include/llmr/renderer/line_bucket.hpp +++ b/include/llmr/renderer/line_bucket.hpp @@ -3,6 +3,7 @@ #include "bucket.hpp" #include +#include #include #include @@ -10,6 +11,7 @@ namespace llmr { class Style; class LineBuffer; +class LineShader; struct Coordinate; struct pbf; @@ -21,10 +23,12 @@ public: void addGeometry(pbf& data); void addGeometry(const std::vector& line); - uint32_t size() const; - void bind(); - char *vertexOffset() const; + size_t size() const; + + void bind(LineShader& shader); + void drawLines(); + void drawPoints(); public: const BucketGeometryDescription geometry; @@ -33,6 +37,7 @@ private: std::shared_ptr buffer; uint32_t start; uint32_t length; + VertexArrayObject array; }; } diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index 108eb2f38..b991c9592 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -2,23 +2,22 @@ #define LLMR_RENDERER_PAINTER #include +#include #include #include +#include +#include +#include +#include + + namespace llmr { class Transform; class Settings; class Style; class Tile; -// class LayerDescription; - -class Shader; -class PlainShader; -class OutlineShader; -class FillShader; -class LineShader; -class PatternShader; class FillBucket; class LineBucket; @@ -33,29 +32,21 @@ public: Painter& operator=(const Painter&) = delete; Painter& operator=(const Painter && ) = delete; - void setup(); - void clear(); void changeMatrix(const Tile::ID& id); void render(const std::shared_ptr& tile); - void renderLayers(const std::shared_ptr& tile, const std::vector& layers); - void renderDebug(const std::shared_ptr& tile); - void renderMatte(); void renderBackground(); void renderFill(FillBucket& bucket, const std::string& layer_name, const Tile::ID& id); void renderLine(LineBucket& bucket, const std::string& layer_name, const Tile::ID& id); - - void drawClippingMask(); - bool switchShader(std::shared_ptr shader); - private: void setupShaders(); - -public: + void drawClippingMask(); + void renderLayers(const std::shared_ptr& tile, const std::vector& layers); + void renderDebug(const std::shared_ptr& tile); private: Transform& transform; @@ -66,12 +57,10 @@ private: mat4 matrix; mat4 exMatrix; - std::shared_ptr currentShader; - std::shared_ptr fillShader; - std::shared_ptr plainShader; - std::shared_ptr outlineShader; - std::shared_ptr lineShader; - std::shared_ptr patternShader; + std::unique_ptr plainShader; + std::unique_ptr outlineShader; + std::unique_ptr lineShader; + std::unique_ptr patternShader; // Set up the stencil quad we're using to generate the stencil mask. VertexBuffer tileStencilBuffer = { @@ -86,6 +75,9 @@ private: 4096, 4096 }; + VertexArrayObject coveringPlainArray; + VertexArrayObject coveringPatternArray; + // Set up the tile boundary lines we're using to draw the tile outlines. VertexBuffer tileBorderBuffer = { 0, 0, @@ -95,6 +87,8 @@ private: 0, 0 }; + VertexArrayObject tileBorderArray; + // Set up the matte buffer we're using to draw the filling background. VertexBuffer matteBuffer = { // top left triangle @@ -108,6 +102,7 @@ private: 16384, 16384 }; + VertexArrayObject matteArray; }; } diff --git a/include/llmr/renderer/shader-fill.hpp b/include/llmr/renderer/shader-fill.hpp deleted file mode 100644 index 440f3011c..000000000 --- a/include/llmr/renderer/shader-fill.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef LLMR_RENDERER_SHADER_FILL -#define LLMR_RENDERER_SHADER_FILL - -#include "shader.hpp" - -namespace llmr { - -class FillShader : public Shader { -public: - FillShader(); - - int32_t a_pos; - int32_t u_matrix; - int32_t u_color; -}; - -} - -#endif diff --git a/include/llmr/renderer/shader-line.hpp b/include/llmr/renderer/shader-line.hpp index 1045a97f3..00e50c1b1 100644 --- a/include/llmr/renderer/shader-line.hpp +++ b/include/llmr/renderer/shader-line.hpp @@ -9,6 +9,8 @@ class LineShader : public Shader { public: LineShader(); + void bind(char *offset); + int32_t a_pos; int32_t a_extrude; int32_t a_linesofar; diff --git a/include/llmr/renderer/shader-outline.hpp b/include/llmr/renderer/shader-outline.hpp index f37c54d5b..c584487e3 100644 --- a/include/llmr/renderer/shader-outline.hpp +++ b/include/llmr/renderer/shader-outline.hpp @@ -9,6 +9,8 @@ class OutlineShader : public Shader { public: OutlineShader(); + void bind(char *offset); + int32_t a_pos; int32_t u_matrix; int32_t u_color; diff --git a/include/llmr/renderer/shader-pattern.hpp b/include/llmr/renderer/shader-pattern.hpp index 5b295cfff..26dac99fa 100644 --- a/include/llmr/renderer/shader-pattern.hpp +++ b/include/llmr/renderer/shader-pattern.hpp @@ -9,6 +9,8 @@ class PatternShader : public Shader { public: PatternShader(); + void bind(char *offset); + int32_t a_pos; int32_t u_matrix; int32_t u_color; diff --git a/include/llmr/renderer/shader-plain.hpp b/include/llmr/renderer/shader-plain.hpp index d1ccdeff0..d38ae5798 100644 --- a/include/llmr/renderer/shader-plain.hpp +++ b/include/llmr/renderer/shader-plain.hpp @@ -9,6 +9,8 @@ class PlainShader : public Shader { public: PlainShader(); + void bind(char *offset); + int32_t a_pos; int32_t u_matrix; int32_t u_color; diff --git a/include/llmr/renderer/shader.hpp b/include/llmr/renderer/shader.hpp index a32d0b647..26674d2d6 100644 --- a/include/llmr/renderer/shader.hpp +++ b/include/llmr/renderer/shader.hpp @@ -1,7 +1,7 @@ #ifndef LLMR_RENDERER_SHADER #define LLMR_RENDERER_SHADER -#include +#include namespace llmr { @@ -18,7 +18,6 @@ public: bool valid; uint32_t program; - std::forward_list attributes; private: bool compileShader(uint32_t *shader, uint32_t type, const char *source); diff --git a/include/llmr/shader/shaders.hpp b/include/llmr/shader/shaders.hpp index 065b8d47f..d3007b2cc 100644 --- a/include/llmr/shader/shaders.hpp +++ b/include/llmr/shader/shaders.hpp @@ -11,7 +11,6 @@ struct shader_source { }; enum { - FILL_SHADER, LINE_SHADER, OUTLINE_SHADER, PATTERN_SHADER, diff --git a/include/llmr/util/pbf.hpp b/include/llmr/util/pbf.hpp index 1813b254f..5585d5c15 100644 --- a/include/llmr/util/pbf.hpp +++ b/include/llmr/util/pbf.hpp @@ -46,20 +46,24 @@ struct pbf { inline void skipValue(uint32_t val); inline void skipBytes(uint32_t bytes); - const uint8_t *data; - const uint8_t *end; - uint32_t value; - uint32_t tag; + const uint8_t *data = NULL; + const uint8_t *end = NULL; + uint32_t value = 0; + uint32_t tag = 0; }; pbf::pbf(const unsigned char *data, uint32_t length) : data(data), - end(data + length) { + end(data + length), + value(0), + tag(0) { } pbf::pbf() : data(NULL), - end(NULL) { + end(NULL), + value(0), + tag(0) { } diff --git a/include/llmr/util/std.hpp b/include/llmr/util/std.hpp new file mode 100644 index 000000000..4ef28d5f8 --- /dev/null +++ b/include/llmr/util/std.hpp @@ -0,0 +1,16 @@ +#ifndef LLMR_UTIL_STD +#define LLMR_UTIL_STD + +#include + +namespace std { + +// C++14 backfill from http://herbsutter.com/gotw/_102/ +template +::std::unique_ptr make_unique(Args&& ...args) { + return ::std::unique_ptr(new T(::std::forward(args)...)); +} + +} + +#endif diff --git a/ios/MBXViewController.mm b/ios/MBXViewController.mm index 48ec2d1c7..560cbd292 100644 --- a/ios/MBXViewController.mm +++ b/ios/MBXViewController.mm @@ -72,6 +72,7 @@ class MBXMapView GLKView *view = (GLKView *)self.view; view.context = self.context; view.drawableStencilFormat = GLKViewDrawableStencilFormat8; + self.preferredFramesPerSecond = 60; [view bindDrawable]; [EAGLContext setCurrentContext:self.context]; diff --git a/src/geometry/vertex_buffer.cpp b/src/geometry/vertex_buffer.cpp index b190e31d8..591b0c13d 100644 --- a/src/geometry/vertex_buffer.cpp +++ b/src/geometry/vertex_buffer.cpp @@ -9,7 +9,6 @@ VertexBuffer::VertexBuffer(std::initializer_list init) : array(init) {} VertexBuffer::~VertexBuffer() { if (buffer != 0) { glDeleteBuffers(1, &buffer); - buffer = 0; } } @@ -26,5 +25,4 @@ void VertexBuffer::bind() { } else { glBindBuffer(GL_ARRAY_BUFFER, buffer); } - } diff --git a/src/map/map.cpp b/src/map/map.cpp index ab29425d9..2828b9d9b 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -94,7 +94,7 @@ void Map::setScale(double scale) { } void Map::setAngle(double angle, double x, double y) { - double dx, dy; + double dx = 0, dy = 0; if (x >= 0 && y >= 0) { dx = (transform.width / 2) - x; diff --git a/src/map/tile.cpp b/src/map/tile.cpp index dccde9383..b7cf468d0 100644 --- a/src/map/tile.cpp +++ b/src/map/tile.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -43,7 +42,6 @@ std::forward_list Tile::children(const ID& id, int32_t z) { Tile::Tile(ID id, const Style& style) : id(id), state(initial), - debugFontBuffer(std::make_shared()), fillBuffer(std::make_shared()), lineBuffer(std::make_shared()), style(style) { @@ -51,7 +49,7 @@ Tile::Tile(ID id, const Style& style) // Initialize tile debug coordinates char coord[32]; snprintf(coord, sizeof(coord), "%d/%d/%d", id.z, id.x, id.y); - debugFontBuffer->addText(coord, 50, 200, 5); + debugFontBuffer.addText(coord, 50, 200, 5); } Tile::~Tile() { diff --git a/src/renderer/fill_bucket.cpp b/src/renderer/fill_bucket.cpp index 69208ae20..6815efb6f 100644 --- a/src/renderer/fill_bucket.cpp +++ b/src/renderer/fill_bucket.cpp @@ -8,8 +8,6 @@ #include -#define BUFFER_OFFSET(i) ((char *)NULL + (i)) - #include struct geometry_too_long_exception : std::exception {}; @@ -97,26 +95,6 @@ void FillBucket::addGeometry(const std::vector& line) { } -void FillBucket::drawElements(int32_t attrib) { - char *vertex_index = BUFFER_OFFSET(vertex_start * 2 * sizeof(int16_t)); - char *elements_index = BUFFER_OFFSET(elements_start * 3 * sizeof(int16_t)); - buffer->bind(); - for (const auto& group : groups) { - glVertexAttribPointer(attrib, 2, GL_SHORT, GL_FALSE, 0, vertex_index); - glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index); - vertex_index += group.vertex_length * 2 * sizeof(uint16_t); - elements_index += group.elements_length * 3 * sizeof(uint16_t); - } -} - -void FillBucket::drawVertices(int32_t attrib) { - // Draw the entire line - char *vertex_index = BUFFER_OFFSET(vertex_start * 2 * sizeof(int16_t)); - buffer->bind(); - glVertexAttribPointer(attrib, 2, GL_SHORT, GL_FALSE, 0, vertex_index); - glDrawArrays(GL_LINE_STRIP, 0, length); -} - void FillBucket::render(Painter& painter, const std::string& layer_name, const Tile::ID& id) { painter.renderFill(*this, layer_name, id); } @@ -125,3 +103,24 @@ 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)); + for (group& group : groups) { + group.array.bind(shader, *buffer, 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); + } +} + +void FillBucket::drawVertices(OutlineShader& shader) { + // Draw the entire line + char *vertex_index = BUFFER_OFFSET(vertex_start * 2 * sizeof(int16_t)); + array.bind(shader, *buffer, vertex_index); + glDrawArrays(GL_LINE_STRIP, 0, length); +} + + diff --git a/src/renderer/line_bucket.cpp b/src/renderer/line_bucket.cpp index 70f766d9d..6e95a7bc6 100644 --- a/src/renderer/line_bucket.cpp +++ b/src/renderer/line_bucket.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -264,14 +265,19 @@ void LineBucket::render(Painter& painter, const std::string& layer_name, const T painter.renderLine(*this, layer_name, id); } -uint32_t LineBucket::size() const { +size_t LineBucket::size() const { return length; } -void LineBucket::bind() { - buffer->bind(); +void LineBucket::bind(LineShader& shader) { + char *vertex_index = BUFFER_OFFSET(start * 4 * sizeof(int16_t)); + array.bind(shader, *buffer, vertex_index); } -char *LineBucket::vertexOffset() const { - return BUFFER_OFFSET(start * 4 * sizeof(int16_t)); +void LineBucket::drawLines() { + glDrawArrays(GL_TRIANGLE_STRIP, 0, length); +} + +void LineBucket::drawPoints() { + glDrawArrays(GL_POINTS, 0, length); } diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 3b5c83caf..8ec633d9b 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -1,15 +1,13 @@ #include #include -#include -#include -#include -#include -#include -#include +#include +#include + #include #include + #include #include #include @@ -24,15 +22,13 @@ using namespace llmr; Painter::Painter(Transform& transform, Settings& settings, Style& style) : transform(transform), settings(settings), - style(style), - currentShader(NULL) { + style(style) { } void Painter::setup() { setupShaders(); - assert(fillShader); assert(plainShader); assert(outlineShader); assert(lineShader); @@ -47,11 +43,10 @@ void Painter::setup() { } void Painter::setupShaders() { - fillShader = std::make_shared(); - plainShader = std::make_shared(); - outlineShader = std::make_shared(); - lineShader = std::make_shared(); - patternShader = std::make_shared(); + plainShader = std::make_unique(); + outlineShader = std::make_unique(); + lineShader = std::make_unique(); + patternShader = std::make_unique(); } void Painter::changeMatrix(const Tile::ID& id) { @@ -76,7 +71,7 @@ void Painter::changeMatrix(const Tile::ID& id) { } void Painter::drawClippingMask() { - switchShader(plainShader); + glUseProgram(plainShader->program); glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, matrix.data()); glColorMask(false, false, false, false); @@ -96,9 +91,10 @@ void Painter::drawClippingMask() { glStencilMask(0xC0); glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP); + + coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0)); + // Draw the clipping mask - tileStencilBuffer.bind(); - glVertexAttribPointer(plainShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0)); glUniform4f(plainShader->u_color, 1.0f, 0.0f, 1.0f, 1.0f); glDrawArrays(GL_TRIANGLES, 0, tileStencilBuffer.length()); @@ -197,11 +193,11 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons glColorMask(false, false, false, false); // Draw the actual triangle fan into the stencil buffer. - switchShader(fillShader); - glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix.data()); + glUseProgram(plainShader->program); + glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, matrix.data()); // Draw all groups - bucket.drawElements(fillShader->a_pos); + bucket.drawElements(*plainShader); // Now that we have the stencil mask in the stencil buffer, we can start // writing to the color buffer. @@ -215,7 +211,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons // Because we're drawing top-to-bottom, and we update the stencil mask // below, we have to draw the outline first (!) if (properties.antialias) { - switchShader(outlineShader); + glUseProgram(outlineShader->program); glUniformMatrix4fv(outlineShader->u_matrix, 1, GL_FALSE, matrix.data()); glLineWidth(2); @@ -238,7 +234,7 @@ 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->a_pos); + bucket.drawVertices(*outlineShader); } // Only draw regions that we marked @@ -257,7 +253,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons fmod(id.y * 4096, imageSize.y) }; - switchShader(patternShader); + glUseProgram(patternShader->program); glUniformMatrix4fv(patternShader->u_matrix, 1, GL_FALSE, matrix.data()); glUniform2f(patternShader->u_pattern_size, imageSize.x, imageSize.y); glUniform2f(patternShader->u_offset, offset.x, offset.y); @@ -268,19 +264,17 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons style.sprite->bind(true); // Draw a rectangle that covers the entire viewport. - tileStencilBuffer.bind(); - glVertexAttribPointer(patternShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0)); + coveringPatternArray.bind(*patternShader, tileStencilBuffer, BUFFER_OFFSET(0)); glDrawArrays(GL_TRIANGLES, 0, tileStencilBuffer.length()); } else { // Draw filling rectangle. - switchShader(fillShader); - glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix.data()); - glUniform4fv(fillShader->u_color, 1, fill_color.data()); + glUseProgram(plainShader->program); + glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, matrix.data()); + glUniform4fv(plainShader->u_color, 1, fill_color.data()); // Draw a rectangle that covers the entire viewport. - tileStencilBuffer.bind(); - glVertexAttribPointer(fillShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0)); + coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0)); glDrawArrays(GL_TRIANGLES, 0, tileStencilBuffer.length()); } @@ -324,42 +318,37 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons // glUniform1f(painter.linepatternShader.u_fade, painter.transform.z % 1.0); } else { - switchShader(lineShader); + 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; + // TODO: Move this to transform? + 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); + 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()); - // } + // 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); + glUniform1f(lineShader->u_point, 0); + bucket.bind(*lineShader); + bucket.drawLines(); - bucket.bind(); - char *vertex_index = bucket.vertexOffset(); - glVertexAttribPointer(lineShader->a_pos, 2, GL_SHORT, false, 8, vertex_index); - glVertexAttribPointer(lineShader->a_extrude, 2, GL_BYTE, false, 8, vertex_index + 6); - glVertexAttribPointer(lineShader->a_linesofar, 1, GL_SHORT, false, 8, vertex_index + 4); - glDrawArrays(GL_TRIANGLE_STRIP, 0, bucket.size()); - - if (bucket.geometry.join == JoinType::Round) { - glUniform1f(lineShader->u_point, 1); - glDrawArrays(GL_POINTS, 0, bucket.size()); + if (bucket.geometry.join == JoinType::Round) { + glUniform1f(lineShader->u_point, 1); + bucket.drawPoints(); + } } // statistics @@ -369,27 +358,23 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons void Painter::renderDebug(const Tile::Ptr& tile) { // Blend to the front, not the back. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glUseProgram(plainShader->program); + glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, matrix.data()); // draw tile outline - switchShader(plainShader); - glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, matrix.data()); - tileBorderBuffer.bind(); - glVertexAttribPointer(plainShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0)); - glUniform4f(plainShader->u_color, 1.0f, 1.0f, 1.0f, 1.0f); + tileBorderArray.bind(*plainShader, tileBorderBuffer, BUFFER_OFFSET(0)); + glUniform4f(plainShader->u_color, 1.0f, 0.0f, 0.0f, 1.0f); glLineWidth(4.0f); glDrawArrays(GL_LINE_STRIP, 0, tileBorderBuffer.length()); // draw debug info - switchShader(plainShader); - glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, matrix.data()); - tile->debugFontBuffer->bind(); - glVertexAttribPointer(plainShader->a_pos, 2, GL_SHORT, GL_FALSE, 0, BUFFER_OFFSET(0)); + tile->debugFontArray.bind(*plainShader, tile->debugFontBuffer, BUFFER_OFFSET(0)); glUniform4f(plainShader->u_color, 1.0f, 1.0f, 1.0f, 1.0f); glLineWidth(4.0f); - glDrawArrays(GL_LINES, 0, tile->debugFontBuffer->length()); + glDrawArrays(GL_LINES, 0, tile->debugFontBuffer.length()); glUniform4f(plainShader->u_color, 0.0f, 0.0f, 0.0f, 1.0f); glLineWidth(2.0f); - glDrawArrays(GL_LINES, 0, tile->debugFontBuffer->length()); + glDrawArrays(GL_LINES, 0, tile->debugFontBuffer.length()); // Revert blending mode to blend to the back. glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE); @@ -398,76 +383,27 @@ void Painter::renderDebug(const Tile::Ptr& tile) { void Painter::renderMatte() { glDisable(GL_STENCIL_TEST); - switchShader(fillShader); - glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, nativeMatrix.data()); + Color white = {{ 0.9, 0.9, 0.9, 1 }}; - Color white = {{ 1, 1, 1, 1 }}; + glUseProgram(plainShader->program); + glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, nativeMatrix.data()); // Draw the clipping mask - matteBuffer.bind(); - glVertexAttribPointer(fillShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0)); - glUniform4fv(fillShader->u_color, 1, white.data()); + matteArray.bind(*plainShader, matteBuffer, BUFFER_OFFSET(0)); + glUniform4fv(plainShader->u_color, 1, white.data()); glDrawArrays(GL_TRIANGLES, 0, matteBuffer.length()); glEnable(GL_STENCIL_TEST); } void Painter::renderBackground() { - switchShader(fillShader); - glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix.data()); - Color white = {{ 1, 1, 1, 1 }}; + glUseProgram(plainShader->program); + glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, matrix.data()); + // Draw the clipping mask - tileStencilBuffer.bind(); - glVertexAttribPointer(fillShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0)); - glUniform4fv(fillShader->u_color, 1, white.data()); + coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0)); + glUniform4fv(plainShader->u_color, 1, white.data()); glDrawArrays(GL_TRIANGLES, 0, tileStencilBuffer.length()); } - - -// Switches to a different shader program. -/** - * @return boolean whether the shader was actually switched - */ -bool Painter::switchShader(std::shared_ptr shader) { - if (currentShader != shader) { - glUseProgram(shader->program); - - // Disable all attributes from the existing shader that aren't used in - // the new shader. Note: attribute indices are *not* program specific! - if (currentShader) { - const std::forward_list& hitherto = currentShader->attributes; - const std::forward_list& henceforth = shader->attributes; - - // Find all attribute indices that are used in the old shader, - // but unused in the new one. - for (uint32_t i : hitherto) { - if (std::find(henceforth.begin(), henceforth.end(), i) == henceforth.end()) { - glDisableVertexAttribArray(i); - } - } - - // Enable all attributes for the new shader that were not already in - // use in the old one. - for (uint32_t i : henceforth) { - if (std::find(hitherto.begin(), hitherto.end(), i) == hitherto.end()) { - glEnableVertexAttribArray(i); - } - } - - currentShader = shader; - } else { - // Enable all attributes for the new shader (== first shader). - for (GLuint index : shader->attributes) { - glEnableVertexAttribArray(index); - } - } - - currentShader = shader; - - return true; - } else { - return false; - } -} diff --git a/src/renderer/shader-fill.cpp b/src/renderer/shader-fill.cpp deleted file mode 100644 index 623d06118..000000000 --- a/src/renderer/shader-fill.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include - -using namespace llmr; - -FillShader::FillShader() - : Shader( - shaders[FILL_SHADER].vertex, - shaders[FILL_SHADER].fragment - ) { - if (!valid) { - fprintf(stderr, "invalid fill shader\n"); - return; - } - - a_pos = glGetAttribLocation(program, "a_pos"); - attributes.emplace_front(a_pos); - - u_matrix = glGetUniformLocation(program, "u_matrix"); - u_color = glGetUniformLocation(program, "u_color"); -} diff --git a/src/renderer/shader-line.cpp b/src/renderer/shader-line.cpp index ae73dbb4f..feed1626e 100644 --- a/src/renderer/shader-line.cpp +++ b/src/renderer/shader-line.cpp @@ -2,6 +2,8 @@ #include #include +#include + using namespace llmr; LineShader::LineShader() @@ -15,11 +17,8 @@ LineShader::LineShader() } 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"); @@ -31,3 +30,14 @@ LineShader::LineShader() u_point = glGetUniformLocation(program, "u_point"); u_gamma = glGetUniformLocation(program, "u_gamma"); } + +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); +} \ No newline at end of file diff --git a/src/renderer/shader-outline.cpp b/src/renderer/shader-outline.cpp index ea27b2698..82d24b316 100644 --- a/src/renderer/shader-outline.cpp +++ b/src/renderer/shader-outline.cpp @@ -2,6 +2,8 @@ #include #include +#include + using namespace llmr; OutlineShader::OutlineShader() @@ -15,9 +17,13 @@ OutlineShader::OutlineShader() } a_pos = glGetAttribLocation(program, "a_pos"); - attributes.emplace_front(a_pos); u_matrix = glGetUniformLocation(program, "u_matrix"); u_color = glGetUniformLocation(program, "u_color"); u_world = glGetUniformLocation(program, "u_world"); } + +void OutlineShader::bind(char *offset) { + glEnableVertexAttribArray(a_pos); + glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset); +} diff --git a/src/renderer/shader-pattern.cpp b/src/renderer/shader-pattern.cpp index 4a921c665..22afd677e 100644 --- a/src/renderer/shader-pattern.cpp +++ b/src/renderer/shader-pattern.cpp @@ -2,6 +2,8 @@ #include #include +#include + using namespace llmr; PatternShader::PatternShader() @@ -15,7 +17,6 @@ PatternShader::PatternShader() } a_pos = glGetAttribLocation(program, "a_pos"); - attributes.emplace_front(a_pos); u_matrix = glGetUniformLocation(program, "u_matrix"); u_color = glGetUniformLocation(program, "u_color"); @@ -25,3 +26,8 @@ PatternShader::PatternShader() u_pattern_br = glGetUniformLocation(program, "u_pattern_br"); u_mix = glGetUniformLocation(program, "u_mix"); } + +void PatternShader::bind(char *offset) { + glEnableVertexAttribArray(a_pos); + glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset); +} diff --git a/src/renderer/shader-plain.cpp b/src/renderer/shader-plain.cpp index 8e767b6dc..e9d06540b 100644 --- a/src/renderer/shader-plain.cpp +++ b/src/renderer/shader-plain.cpp @@ -2,6 +2,8 @@ #include #include +#include + using namespace llmr; PlainShader::PlainShader() @@ -15,8 +17,12 @@ PlainShader::PlainShader() } a_pos = glGetAttribLocation(program, "a_pos"); - attributes.emplace_front(a_pos); u_matrix = glGetUniformLocation(program, "u_matrix"); u_color = glGetUniformLocation(program, "u_color"); } + +void PlainShader::bind(char *offset) { + glEnableVertexAttribArray(a_pos); + glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset); +} diff --git a/src/renderer/shader.cpp b/src/renderer/shader.cpp index f2326efd7..fd74281bf 100644 --- a/src/renderer/shader.cpp +++ b/src/renderer/shader.cpp @@ -107,7 +107,7 @@ bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source) { #if defined(EMSCRIPTEN) || defined(GL_ES_VERSION_2_0) // Add WebGL GLSL / OpenGL ES precision premable - const GLchar *preamble = "precision mediump float;\n\n"; + const GLchar *preamble = "precision highp float;\n\n"; #else // Desktop GLSL const GLchar *preamble = "#version 120\n\n"; diff --git a/src/shader/fill.fragment.glsl b/src/shader/fill.fragment.glsl deleted file mode 100644 index 8df552c17..000000000 --- a/src/shader/fill.fragment.glsl +++ /dev/null @@ -1,5 +0,0 @@ -uniform vec4 u_color; - -void main() { - gl_FragColor = u_color; -} diff --git a/src/shader/fill.vertex.glsl b/src/shader/fill.vertex.glsl deleted file mode 100644 index 866c3cd2f..000000000 --- a/src/shader/fill.vertex.glsl +++ /dev/null @@ -1,7 +0,0 @@ -attribute vec2 a_pos; - -uniform mat4 u_matrix; - -void main() { - gl_Position = u_matrix * vec4(a_pos, 0, 1); -} diff --git a/src/shader/shaders.cpp b/src/shader/shaders.cpp index 3d0b98bc6..94d1759fe 100644 --- a/src/shader/shaders.cpp +++ b/src/shader/shaders.cpp @@ -4,10 +4,6 @@ using namespace llmr; const shader_source llmr::shaders[SHADER_COUNT] = { - { - "attribute vec2 a_pos;\n\nuniform mat4 u_matrix;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n}\n", - "uniform vec4 u_color;\n\nvoid main() {\n gl_FragColor = u_color;\n}\n", - }, { "// 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", "// 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",