Merge branch 'tessellation' into nostencil
Conflicts: include/llmr/renderer/fill_bucket.hpp src/renderer/painter.cpp
This commit is contained in:
@@ -183,8 +183,22 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
|
||||
fill_color[2] *= properties.opacity;
|
||||
fill_color[3] *= properties.opacity;
|
||||
|
||||
// Draw the stencil mask.
|
||||
{
|
||||
bool outline = properties.antialias && properties.stroke_color != properties.fill_color;
|
||||
bool fringeline = properties.antialias && properties.stroke_color == properties.fill_color;
|
||||
|
||||
// Because we're drawing top-to-bottom, and we update the stencil mask
|
||||
// below, we have to draw the outline first (!)
|
||||
if (outline) {
|
||||
useProgram(outlineShader->program);
|
||||
outlineShader->setMatrix(matrix);
|
||||
lineWidth(2.0f); // This is always fixed and does not depend on the pixelRatio!
|
||||
|
||||
outlineShader->setColor(properties.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);
|
||||
@@ -194,70 +208,14 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
|
||||
// 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);
|
||||
glStencilFunc(GL_EQUAL, 0x80, 0x80);
|
||||
|
||||
if (properties.winding == Winding::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.
|
||||
useProgram(plainShader->program);
|
||||
plainShader->setMatrix(matrix);
|
||||
|
||||
// Draw all groups
|
||||
bucket.drawElements(*plainShader);
|
||||
|
||||
// Now that we have the stencil mask in the stencil buffer, we can start
|
||||
// writing to the color buffer.
|
||||
glColorMask(true, true, true, true);
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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 (properties.antialias) {
|
||||
useProgram(outlineShader->program);
|
||||
outlineShader->setMatrix(matrix);
|
||||
lineWidth(2.0f); // This is always fixed and does not depend on the pixelRatio!
|
||||
|
||||
if (properties.stroke_color != properties.fill_color) {
|
||||
// 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);
|
||||
outlineShader->setColor(properties.stroke_color);
|
||||
} 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);
|
||||
outlineShader->setColor(fill_color);
|
||||
}
|
||||
|
||||
// Draw the entire line
|
||||
outlineShader->setWorld({{ transform.fb_width, transform.fb_height }});
|
||||
bucket.drawVertices(*outlineShader);
|
||||
}
|
||||
|
||||
// Only draw regions that we marked
|
||||
glStencilFunc(GL_NOTEQUAL, 0x0, 0x3F);
|
||||
|
||||
if (properties.image.size() && *style.sprite) {
|
||||
// Draw texture fill
|
||||
ImagePosition imagePos = style.sprite->getPosition(properties.image, true);
|
||||
@@ -266,14 +224,16 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
|
||||
float mix = fmod(transform.getZoom(), 1.0);
|
||||
|
||||
std::array<float, 2> imageSize = {{
|
||||
imagePos.size.x * factor,
|
||||
imagePos.size.y * factor
|
||||
}};
|
||||
imagePos.size.x * factor,
|
||||
imagePos.size.y *factor
|
||||
}
|
||||
};
|
||||
|
||||
std::array<float, 2> offset = {{
|
||||
(float)fmod(id.x * 4096, imageSize[0]),
|
||||
(float)fmod(id.y * 4096, imageSize[1])
|
||||
}};
|
||||
(float)fmod(id.x * 4096, imageSize[0]),
|
||||
(float)fmod(id.y * 4096, imageSize[1])
|
||||
}
|
||||
};
|
||||
|
||||
useProgram(patternShader->program);
|
||||
patternShader->setMatrix(matrix);
|
||||
@@ -285,22 +245,43 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
|
||||
patternShader->setMix(mix);
|
||||
style.sprite->bind(true);
|
||||
|
||||
// Draw a rectangle that covers the entire viewport.
|
||||
coveringPatternArray.bind(*patternShader, tileStencilBuffer, BUFFER_OFFSET(0));
|
||||
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index());
|
||||
|
||||
// Draw the actual triangles into the color & stencil buffer.
|
||||
bucket.drawElements(*patternShader);
|
||||
} else {
|
||||
// Draw filling rectangle.
|
||||
useProgram(plainShader->program);
|
||||
plainShader->setMatrix(matrix);
|
||||
plainShader->setColor(fill_color);
|
||||
|
||||
// Draw a rectangle that covers the entire viewport.
|
||||
coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0));
|
||||
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index());
|
||||
// Draw the actual triangles into the color & stencil buffer.
|
||||
bucket.drawElements(*plainShader);
|
||||
}
|
||||
|
||||
glStencilFunc(GL_EQUAL, 0x80, 0x80);
|
||||
// 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!
|
||||
|
||||
// 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);
|
||||
|
||||
// Draw the entire line
|
||||
outlineShader->setWorld({{ transform.fb_width, transform.fb_height }});
|
||||
bucket.drawVertices(*outlineShader);
|
||||
|
||||
glStencilFunc(GL_EQUAL, 0x80, 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, const Tile::ID& id) {
|
||||
@@ -330,20 +311,22 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons
|
||||
linejoinShader->setMatrix(matrix);
|
||||
linejoinShader->setColor(color);
|
||||
linejoinShader->setWorld({{
|
||||
transform.fb_width * 0.5f,
|
||||
transform.fb_height * 0.5f
|
||||
}});
|
||||
transform.fb_width * 0.5f,
|
||||
transform.fb_height * 0.5f
|
||||
}
|
||||
});
|
||||
linejoinShader->setLineWidth({{
|
||||
((outset - 0.25f) * transform.pixelRatio),
|
||||
((inset - 0.25f) * transform.pixelRatio)
|
||||
}});
|
||||
((outset - 0.25f) * transform.pixelRatio),
|
||||
((inset - 0.25f) * transform.pixelRatio)
|
||||
}
|
||||
});
|
||||
|
||||
float pointSize = ceil(transform.pixelRatio * outset * 2.0);
|
||||
#if defined(GL_ES_VERSION_2_0)
|
||||
#if defined(GL_ES_VERSION_2_0)
|
||||
linejoinShader->setSize(pointSize);
|
||||
#else
|
||||
#else
|
||||
glPointSize(pointSize);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bucket.drawPoints(*linejoinShader);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user