diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2014-01-22 18:07:30 +0100 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2014-01-22 18:07:30 +0100 |
commit | 1ad5970a0001b9dd7ca0bd521b361f0f15c65d0d (patch) | |
tree | deea47dcc40167cb56da1a1d5d825859d0baff0f /src | |
parent | 0f74a4bc90e1d4d69b50a443aa9f1ed42d071d4d (diff) | |
download | qtlocation-mapboxgl-1ad5970a0001b9dd7ca0bd521b361f0f15c65d0d.tar.gz |
render shapes, but only the first one is drawn?
Diffstat (limited to 'src')
-rw-r--r-- | src/geometry/debug_font_buffer.cpp | 1 | ||||
-rw-r--r-- | src/geometry/linevertexbuffer.cpp | 1 | ||||
-rw-r--r-- | src/map/tile.cpp | 2 | ||||
-rw-r--r-- | src/renderer/painter.cpp | 165 |
4 files changed, 150 insertions, 19 deletions
diff --git a/src/geometry/debug_font_buffer.cpp b/src/geometry/debug_font_buffer.cpp index e2086ef42a..a383ca5734 100644 --- a/src/geometry/debug_font_buffer.cpp +++ b/src/geometry/debug_font_buffer.cpp @@ -15,6 +15,7 @@ debug_font_buffer::debug_font_buffer() debug_font_buffer::~debug_font_buffer() { if (buffer != 0) { glDeleteBuffers(1, &buffer); + buffer = 0; } } diff --git a/src/geometry/linevertexbuffer.cpp b/src/geometry/linevertexbuffer.cpp index 2086a0e865..3c8521bc39 100644 --- a/src/geometry/linevertexbuffer.cpp +++ b/src/geometry/linevertexbuffer.cpp @@ -12,6 +12,7 @@ linevertexbuffer::linevertexbuffer() linevertexbuffer::~linevertexbuffer() { if (buffer != 0) { glDeleteBuffers(1, &buffer); + buffer = 0; } } diff --git a/src/map/tile.cpp b/src/map/tile.cpp index 1d4a660ac5..4d744cb971 100644 --- a/src/map/tile.cpp +++ b/src/map/tile.cpp @@ -51,6 +51,8 @@ Tile::Tile(ID id) } Tile::~Tile() { + std::lock_guard<std::mutex> lock(mtx); + // fprintf(stderr, "[%p] deleting tile %d/%d/%d\n", this, id.z, id.x, id.y); if (this->data) { free(this->data); diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 02269a76b7..af5ecb55dd 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -8,6 +8,8 @@ #include <llmr/platform/gl.hpp> #include <llmr/map/settings.hpp> +#include <cmath> + #include <numeric> using namespace llmr; @@ -59,9 +61,10 @@ void Painter::setup() { glEnable(GL_STENCIL_TEST); - + // We are blending the new pixels *behind* the existing pixels. That way we can + // draw front-to-back and use then stencil buffer to cull opaque pixels early. glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE); } void Painter::setupShaders() { @@ -131,7 +134,7 @@ void Painter::drawClippingMask() { } void Painter::clear() { - glClearColor(1.0f, 1.0f, 0.0f, 1.0f); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearStencil(0x0); glStencilMask(0xFF); glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); @@ -162,37 +165,146 @@ void Painter::render(const Tile::Ptr& tile) { glDrawArrays(GL_LINE_STRIP, 0, tile->lineVertex.length()); // draw fills: + + // TODO: expose this to the stylesheet + bool evenodd = false; + bool antialiasing = true; + + tile->fillBuffer.bind(); float i = 0.0f; + fprintf(stderr, "----\n"); for (const Tile::fill_index& index : tile->fillIndices) { + float color[] = { i, i, 1.0f, 1.0f }; + i = sqrt(i); if (!index.length) continue; + // if (index.name != "water") continue; + fprintf(stderr, "%s: %d\n", index.name.c_str(), index.length); + + + glStencilMask(0x0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_EQUAL, 0x80, 0x80); + glColorMask(true, true, true, true); + + // Draw the stencil mask. + { + // We're only drawing to the first seven bits (== support a maximum of + // 127 overlapping polygons in one place before we get rendering errors). + glStencilMask(0x3F); + glClear(GL_STENCIL_BUFFER_BIT); + + // Draw front facing triangles. Wherever the 0x80 bit is 1, we are + // increasing the lower 7 bits by one if the triangle is a front-facing + // triangle. This means that all visible polygons should be in CCW + // orientation, while all holes (see below) are in CW orientation. + glStencilFunc(GL_NOTEQUAL, 0x80, 0x80); + + if (evenodd) { + // When we draw an even/odd winding fill, we just invert all the bits. + glStencilOp(GL_INVERT, GL_KEEP, GL_KEEP); + } else { + // When we do a nonzero fill, we count the number of times a pixel is + // covered by a counterclockwise polygon, and subtract the number of + // times it is "uncovered" by a clockwise polygon. + glStencilOpSeparate(GL_FRONT, GL_INCR_WRAP, GL_KEEP, GL_KEEP); + glStencilOpSeparate(GL_BACK, GL_DECR_WRAP, GL_KEEP, GL_KEEP); + } + + // When drawing a shape, we first draw all shapes to the stencil buffer + // and incrementing all areas where polygons are + glColorMask(false, false, false, false); + + // Draw the actual triangle fan into the stencil buffer. + switchShader(fillShader); + glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix); + + // Draw all groups + char *vertex_index = BUFFER_OFFSET(index.vertex_start * 2 * sizeof(uint16_t)); + char *elements_index = BUFFER_OFFSET(index.elements_start * 3 * sizeof(uint16_t)); + for (const Tile::fill_index::group& group : index.groups) { + fprintf(stderr, "- vertex: %d, elements: %d, length: %d\n", vertex_index, elements_index, group.elements_length * 3); + + glVertexAttribPointer(fillShader->a_pos, 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); + } + + // Now that we have the stencil mask in the stencil buffer, we can start + // writing to the color buffer. + glColorMask(true, true, true, true); + } - glUniform4f(outlineShader->u_color, i, 0.0f, 1.0f, 0.5f); - glUniform2f(outlineShader->u_world, transform.fb_width, transform.fb_height); - glLineWidth(2.0f); - - char *vertex_index = BUFFER_OFFSET(index.vertex_start * 2 * sizeof(uint16_t)); - char *elements_index = BUFFER_OFFSET(index.elements_start * 3 * sizeof(uint16_t)); - for (const Tile::fill_index::group& group : index.groups) { - glVertexAttribPointer(outlineShader->a_pos, 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); + // From now on, we don't want to update the stencil buffer anymore. + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilMask(0x0); + + // // Because we're drawing top-to-bottom, and we update the stencil mask + // // below, we have to draw the outline first (!) + // if (antialiasing) { + + // // if (layerStyle.stroke) { + // // // If we defined a different color for the fill outline, we are + // // // going to ignore the bits in 0x3F and just care about the global + // // // clipping mask. + // // glStencilFunc(GL_EQUAL, 0x80, 0x80); + // // } else { + // // Otherwise, we only want to draw the antialiased parts that are + // // *outside* the current shape. This is important in case the fill + // // or stroke color is translucent. If we wouldn't clip to outside + // // the current shape, some pixels from the outline stroke overlapped + // // the (non-antialiased) fill. + // glStencilFunc(GL_EQUAL, 0x80, 0xBF); + // // } + + // switchShader(outlineShader); + // glUniformMatrix4fv(outlineShader->u_matrix, 1, GL_FALSE, matrix); + // glUniform2f(outlineShader->u_world, transform.fb_width, transform.fb_height); + // glUniform4f(outlineShader->u_color, color[0], color[1], color[2], color[3]); + // glLineWidth(2); + + // // Draw the entire line + // char *vertex_index = BUFFER_OFFSET(index.vertex_start * 2 * sizeof(uint16_t)); + // glVertexAttribPointer(outlineShader->a_pos, 2, GL_SHORT, GL_FALSE, 0, vertex_index); + // glLineWidth(2.0f); + // glDrawArrays(GL_LINE_STRIP, 0, index.length); + // } + + // Now finally, draw a tile-covering quad that paints the parts of the + // image that we marked in the stencil buffer. + { + // Only draw regions that we marked + glStencilFunc(GL_NOTEQUAL, 0x0, 0x3F); + + switchShader(fillShader); + glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix); + + // Draw a rectangle that covers the entire viewport. + glBindBuffer(GL_ARRAY_BUFFER, tile_stencil_buffer); + glVertexAttribPointer(fillShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0)); + glUniform4f(fillShader->u_color, color[0], color[1], color[2], color[3]); + glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(tile_stencil_vertices)); + + glStencilMask(0x00); + glStencilFunc(GL_EQUAL, 0x80, 0x80); } - vertex_index = BUFFER_OFFSET(index.vertex_start * 2 * sizeof(uint16_t)); - glUniform4f(outlineShader->u_color, i, 1.0f, 1.0f, 1.0f); - glVertexAttribPointer(outlineShader->a_pos, 2, GL_SHORT, GL_FALSE, 0, vertex_index); - glDrawArrays(GL_LINE_STRIP, 0, index.length); - i += 0.1f; + + // break; } if (settings.debug) { renderDebug(tile); } + + renderBackground(); } void Painter::renderDebug(const Tile::Ptr& tile) { + // Blend to the front, not the back. + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + // draw tile outline switchShader(lineShader); glUniformMatrix4fv(lineShader->u_matrix, 1, GL_FALSE, matrix); @@ -213,8 +325,23 @@ void Painter::renderDebug(const Tile::Ptr& tile) { glUniform4f(lineShader->u_color, 0.0f, 0.0f, 0.0f, 1.0f); glLineWidth(2.0f); glDrawArrays(GL_LINES, 0, tile->debugFontVertex.length()); + + // Revert blending mode to blend to the back. + glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE); +} + +void Painter::renderBackground() { + switchShader(fillShader); + glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix); + + // Draw the clipping mask + glBindBuffer(GL_ARRAY_BUFFER, tile_stencil_buffer); + glVertexAttribPointer(fillShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0)); + glUniform4f(fillShader->u_color, 1.0f, 1.0f, 1.0f, 1.0f); + glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(tile_stencil_vertices)); } + // Switches to a different shader program. /** * @return boolean whether the shader was actually switched |