draw a checkerboard stencil clipping mask initially

This commit is contained in:
Konstantin Käfer
2014-02-26 12:24:17 +01:00
parent 70ec13e302
commit 8d68bd73e7
5 changed files with 90 additions and 78 deletions

View File

@@ -2,6 +2,7 @@
#define LLMR_MAP_TILE
#include <llmr/util/vec.hpp>
#include <llmr/util/mat4.hpp>
#include <llmr/util/noncopyable.hpp>
#include <llmr/geometry/debug_font_buffer.hpp>
#include <llmr/geometry/vao.hpp>
@@ -71,6 +72,7 @@ public:
public:
const ID id;
uint8_t clip_id;
state state;
// Holds the actual geometries in this tile.
@@ -89,6 +91,7 @@ public:
// They contain the location offsets in the buffers stored above
std::map<std::string, std::shared_ptr<Bucket>> buckets;
mat4 matrix;
private:
// Source data
std::string data;

View File

@@ -32,7 +32,7 @@ public:
void setup();
void clear();
void changeMatrix(const Tile::ID& id);
void changeMatrix();
void render(const std::shared_ptr<Tile>& tile);
void renderMatte();
void renderBackground();
@@ -40,24 +40,28 @@ public:
void renderLine(LineBucket& bucket, const std::string& layer_name, const Tile::ID& id);
void renderPoint(PointBucket& bucket, const std::string& layer_name, const Tile::ID& id);
void prepareClippingMask();
void drawClippingMask(const mat4& matrix, uint8_t clip_id);
void finishClippingMask();
private:
void setupShaders();
void drawClippingMask();
void renderLayers(const std::shared_ptr<Tile>& tile, const std::vector<LayerDescription>& layers);
void renderDebug(const std::shared_ptr<Tile>& tile);
void useProgram(uint32_t program);
void lineWidth(float lineWidth);
public:
mat4 matrix;
mat4 projMatrix;
mat4 nativeMatrix;
mat4 extrudeMatrix;
private:
Transform& transform;
Settings& settings;
Style& style;
mat4 nativeMatrix;
mat4 matrix;
mat4 exMatrix;
uint32_t gl_program = 0;
float gl_lineWidth = 0;

View File

@@ -227,7 +227,6 @@ public:
};
MapView *mapView;
NSOperationQueue *queue;
namespace llmr {
namespace platform {
@@ -240,10 +239,6 @@ void restart() {
}
void request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback) {
if (!queue) {
queue = [NSOperationQueue new];
}
NSMutableURLRequest *urlRequest = [NSMutableURLRequest
requestWithURL:[NSURL
URLWithString:@(url.c_str())]];

View File

@@ -414,10 +414,26 @@ bool Map::render() {
painter.clear();
painter.changeMatrix();
// First, update all tile matrices with the new transform and render into
// the stencil buffer.
uint8_t i = 1;
painter.prepareClippingMask();
for (Tile::Ptr& tile : tiles) {
assert(tile);
if (tile->state == Tile::ready) {
painter.changeMatrix(tile->id);
// The position matrix.
transform.matrixFor(tile->matrix, tile->id);
matrix::multiply(tile->matrix, painter.projMatrix, tile->matrix);
tile->clip_id = i++;
painter.drawClippingMask(tile->matrix, tile->clip_id);
}
}
painter.finishClippingMask();
for (Tile::Ptr& tile : tiles) {
if (tile->state == Tile::ready) {
painter.render(tile);
}
}

View File

@@ -71,19 +71,14 @@ void Painter::lineWidth(float lineWidth) {
}
}
void Painter::changeMatrix(const Tile::ID& id) {
void Painter::changeMatrix() {
// Initialize projection matrix
mat4 projMatrix;
matrix::ortho(projMatrix, 0, transform.width, transform.height, 0, 1, 10);
// The position matrix.
transform.matrixFor(matrix, id);
matrix::multiply(matrix, projMatrix, matrix);
// The extrusion matrix.
matrix::identity(exMatrix);
matrix::multiply(exMatrix, projMatrix, exMatrix);
matrix::rotate_z(exMatrix, exMatrix, transform.getAngle());
matrix::identity(extrudeMatrix);
matrix::multiply(extrudeMatrix, projMatrix, extrudeMatrix);
matrix::rotate_z(extrudeMatrix, extrudeMatrix, transform.getAngle());
// The native matrix is a 1:1 matrix that paints the coordinates at the
// same screen position as the vertex specifies.
@@ -92,38 +87,26 @@ void Painter::changeMatrix(const Tile::ID& id) {
matrix::multiply(nativeMatrix, projMatrix, nativeMatrix);
}
void Painter::drawClippingMask() {
void Painter::prepareClippingMask() {
useProgram(plainShader->program);
plainShader->setMatrix(matrix);
glColorMask(false, false, false, false);
// Clear the entire stencil buffer, except for the 7th bit, which stores
// the global clipping mask that allows us to avoid drawing in regions of
// tiles we've already painted in.
glStencilMask(0xBF);
glClear(GL_STENCIL_BUFFER_BIT);
// The stencil test will fail always, meaning we set all pixels covered
// by this geometry to 0x80. We use the highest bit 0x80 to mark the regions
// we want to draw in. All pixels that have this bit *not* set will never be
// drawn in.
glStencilFunc(GL_EQUAL, 0xC0, 0x40);
glStencilMask(0xC0);
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0));
}
// Draw the clipping mask
plainShader->setColor(1.0f, 0.0f, 1.0f, 1.0f);
void Painter::drawClippingMask(const mat4& matrix, uint8_t clip_id) {
plainShader->setMatrix(matrix);
glStencilFunc(GL_ALWAYS, clip_id, 0xFF);
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index());
}
// glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x80, 0x80);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0x00);
void Painter::finishClippingMask() {
glColorMask(true, true, true, true);
glEnable(GL_STENCIL_TEST);
glStencilMask(0x0);
}
void Painter::clear() {
@@ -136,7 +119,8 @@ void Painter::render(const Tile::Ptr& tile) {
return;
}
drawClippingMask();
matrix = tile->matrix;
glStencilFunc(GL_EQUAL, tile->clip_id, 0xFF);
renderLayers(tile, style.layers);
@@ -183,8 +167,18 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
fill_color[2] *= properties.opacity;
fill_color[3] *= properties.opacity;
Color stroke_color = properties.stroke_color;
stroke_color[0] *= properties.opacity;
stroke_color[1] *= properties.opacity;
stroke_color[2] *= properties.opacity;
stroke_color[3] *= properties.opacity;
bool outline = properties.antialias && properties.stroke_color != properties.fill_color;
bool fringeline = properties.antialias && properties.stroke_color == properties.fill_color;
if (fringeline) {
outline = true;
stroke_color = fill_color;
}
// Because we're drawing top-to-bottom, and we update the stencil mask
// below, we have to draw the outline first (!)
@@ -193,27 +187,27 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
outlineShader->setMatrix(matrix);
lineWidth(2.0f); // This is always fixed and does not depend on the pixelRatio!
outlineShader->setColor(properties.stroke_color);
outlineShader->setColor(stroke_color);
// Draw the entire line
outlineShader->setWorld({{ transform.fb_width, transform.fb_height }});
bucket.drawVertices(*outlineShader);
} else if (fringeline) {
// 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);
// // 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_EQUAL, 0x80, 0x80);
// // 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_EQUAL, 0x80, 0x80);
// 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.
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP);
// // 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.
// glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP);
}
if (properties.image.size() && *style.sprite) {
@@ -260,27 +254,27 @@ 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 (fringeline) {
useProgram(outlineShader->program);
outlineShader->setMatrix(matrix);
lineWidth(2.0f); // This is always fixed and does not depend on the pixelRatio!
// useProgram(outlineShader->program);
// outlineShader->setMatrix(matrix);
// lineWidth(2.0f); // This is always fixed and does not depend on the pixelRatio!
// From now on, we don't want to update the stencil buffer anymore.
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0x0);
// // From now on, we don't want to update the stencil buffer anymore.
// glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
// glStencilMask(0x0);
// 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);
outlineShader->setColor(fill_color);
// // 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);
// outlineShader->setColor(fill_color);
// Draw the entire line
outlineShader->setWorld({{ transform.fb_width, transform.fb_height }});
bucket.drawVertices(*outlineShader);
// // Draw the entire line
// outlineShader->setWorld({{ transform.fb_width, transform.fb_height }});
// bucket.drawVertices(*outlineShader);
glStencilFunc(GL_EQUAL, 0x80, 0x80);
// glStencilFunc(GL_EQUAL, 0x80, 0x80);
}
}
@@ -339,7 +333,7 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons
// imageSprite.bind(gl, true);
// //factor = Math.pow(2, 4 - painter.transform.zoom + params.z);
// gl.switchShader(painter.linepatternShader, painter.translatedMatrix || painter.posMatrix, painter.exMatrix);
// 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);
@@ -349,7 +343,7 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons
} else {
useProgram(lineShader->program);
lineShader->setMatrix(matrix);
lineShader->setExtrudeMatrix(exMatrix);
lineShader->setExtrudeMatrix(extrudeMatrix);
// TODO: Move this to transform?
const float tilePixelRatio = transform.getScale() / (1 << transform.getIntegerZoom()) / 8;