summaryrefslogtreecommitdiff
path: root/src/mbgl/renderer/painter_fill.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/renderer/painter_fill.cpp')
-rw-r--r--src/mbgl/renderer/painter_fill.cpp243
1 files changed, 99 insertions, 144 deletions
diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp
index 95e514298a..b386e227d5 100644
--- a/src/mbgl/renderer/painter_fill.cpp
+++ b/src/mbgl/renderer/painter_fill.cpp
@@ -1,14 +1,12 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/gl/gl.hpp>
-#include <mbgl/map/view.hpp>
-
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/fill_layer_impl.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/shader/shaders.hpp>
+#include <mbgl/shader/fill_uniforms.hpp>
#include <mbgl/util/convert.hpp>
namespace mbgl {
@@ -20,159 +18,116 @@ void Painter::renderFill(PaintParameters& parameters,
const FillLayer& layer,
const RenderTile& tile) {
const FillPaintProperties& properties = layer.impl->paint;
- mat4 vertexMatrix = tile.translatedMatrix(properties.fillTranslate,
- properties.fillTranslateAnchor,
- state);
-
- Color fillColor = properties.fillColor;
- float opacity = properties.fillOpacity;
-
- const bool isOutlineColorDefined = !properties.fillOutlineColor.isUndefined();
- Color strokeColor = isOutlineColorDefined? properties.fillOutlineColor : fillColor;
-
- const auto viewport = context.viewport.getCurrentValue();
- const std::array<GLfloat, 2> worldSize{{ static_cast<GLfloat>(viewport.size.width),
- static_cast<GLfloat>(viewport.size.height) }};
-
- bool pattern = !properties.fillPattern.value.from.empty();
- bool outline = properties.fillAntialias && !pattern && isOutlineColorDefined;
- bool fringeline = properties.fillAntialias && !pattern && !isOutlineColorDefined;
-
- context.stencilOp = { gl::StencilTestOperation::Keep, gl::StencilTestOperation::Keep,
- gl::StencilTestOperation::Replace };
- context.stencilTest = true;
- context.depthFunc = gl::DepthTestFunction::LessEqual;
- context.depthTest = true;
- context.depthMask = true;
- context.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio!
-
- auto& outlineShader = parameters.shaders.fillOutline;
- auto& patternShader = parameters.shaders.fillPattern;
- auto& outlinePatternShader = parameters.shaders.fillOutlinePattern;
- auto& plainShader = parameters.shaders.fill;
- // Because we're drawing top-to-bottom, and we update the stencil mask
- // befrom, we have to draw the outline first (!)
- if (outline && pass == RenderPass::Translucent) {
- context.program = outlineShader.getID();
- outlineShader.u_matrix = vertexMatrix;
-
- outlineShader.u_outline_color = strokeColor;
- outlineShader.u_opacity = opacity;
-
- // Draw the entire line
- outlineShader.u_world = worldSize;
- if (isOutlineColorDefined) {
- // If we defined a different color for the fill outline, we are
- // going to ignore the bits in 0x07 and just care about the global
- // clipping mask.
- setDepthSublayer(2); // OK
- } else {
- // Otherwise, we only want to drawFill 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.
- setDepthSublayer(0); // OK
+ if (!properties.fillPattern.value.from.empty()) {
+ if (pass != RenderPass::Translucent) {
+ return;
}
- bucket.drawVertices(outlineShader, context, paintMode());
- }
- if (pattern) {
optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition(
properties.fillPattern.value.from, SpritePatternMode::Repeating);
- optional<SpriteAtlasPosition> imagePosB =
- spriteAtlas->getPosition(properties.fillPattern.value.to, SpritePatternMode::Repeating);
-
- // Image fill.
- if (pass == RenderPass::Translucent && imagePosA && imagePosB) {
- context.program = patternShader.getID();
- patternShader.u_matrix = vertexMatrix;
- patternShader.u_pattern_tl_a = imagePosA->tl;
- patternShader.u_pattern_br_a = imagePosA->br;
- patternShader.u_pattern_tl_b = imagePosB->tl;
- patternShader.u_pattern_br_b = imagePosB->br;
- patternShader.u_opacity = properties.fillOpacity;
- patternShader.u_image = 0;
- patternShader.u_mix = properties.fillPattern.value.t;
- patternShader.u_pattern_size_a = imagePosA->size;
- patternShader.u_pattern_size_b = imagePosB->size;
- patternShader.u_scale_a = properties.fillPattern.value.fromScale;
- patternShader.u_scale_b = properties.fillPattern.value.toScale;
- patternShader.u_tile_units_to_pixels = 1.0f / tile.id.pixelsToTileUnits(1.0f, state.getIntegerZoom());
-
- GLint tileSizeAtNearestZoom = util::tileSize * state.zoomScale(state.getIntegerZoom() - tile.id.canonical.z);
- GLint pixelX = tileSizeAtNearestZoom * (tile.id.canonical.x + tile.id.wrap * state.zoomScale(tile.id.canonical.z));
- GLint pixelY = tileSizeAtNearestZoom * tile.id.canonical.y;
- patternShader.u_pixel_coord_upper = {{ float(pixelX >> 16), float(pixelY >> 16) }};
- patternShader.u_pixel_coord_lower = {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }};
-
- spriteAtlas->bind(true, context, 0);
+ optional<SpriteAtlasPosition> imagePosB = spriteAtlas->getPosition(
+ properties.fillPattern.value.to, SpritePatternMode::Repeating);
- // Draw the actual triangles into the color & stencil buffer.
- setDepthSublayer(0);
- bucket.drawElements(patternShader, context, paintMode());
-
- if (properties.fillAntialias && !isOutlineColorDefined) {
- context.program = outlinePatternShader.getID();
- outlinePatternShader.u_matrix = vertexMatrix;
-
- outlinePatternShader.u_pattern_tl_a = imagePosA->tl;
- outlinePatternShader.u_pattern_br_a = imagePosA->br;
- outlinePatternShader.u_pattern_tl_b = imagePosB->tl;
- outlinePatternShader.u_pattern_br_b = imagePosB->br;
- outlinePatternShader.u_opacity = properties.fillOpacity;
- outlinePatternShader.u_image = 0;
- outlinePatternShader.u_mix = properties.fillPattern.value.t;
- outlinePatternShader.u_pattern_size_a = imagePosA->size;
- outlinePatternShader.u_pattern_size_b = imagePosB->size;
- outlinePatternShader.u_scale_a = properties.fillPattern.value.fromScale;
- outlinePatternShader.u_scale_b = properties.fillPattern.value.toScale;
- outlinePatternShader.u_tile_units_to_pixels = 1.0f / tile.id.pixelsToTileUnits(1.0f, state.getIntegerZoom());
- outlinePatternShader.u_pixel_coord_upper = {{ float(pixelX >> 16), float(pixelY >> 16) }};
- outlinePatternShader.u_pixel_coord_lower = {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }};
-
- // Draw the entire line
- outlinePatternShader.u_world = worldSize;
-
- spriteAtlas->bind(true, context, 0);
-
- setDepthSublayer(2);
- bucket.drawVertices(outlinePatternShader, context, paintMode());
- }
+ if (!imagePosA || !imagePosB) {
+ return;
}
- } else {
- // No image fill.
- if ((fillColor.a >= 1.0f && opacity >= 1.0f) == (pass == RenderPass::Opaque)) {
- // Only draw the fill when it's either opaque and we're drawing opaque
- // fragments or when it's translucent and we're drawing translucent
- // fragments
- // Draw filling rectangle.
- context.program = plainShader.getID();
- plainShader.u_matrix = vertexMatrix;
- plainShader.u_color = fillColor;
- plainShader.u_opacity = opacity;
- // Draw the actual triangles into the color & stencil buffer.
- setDepthSublayer(1);
- bucket.drawElements(plainShader, context, paintMode());
+ spriteAtlas->bind(true, context, 0);
+
+ auto draw = [&] (uint8_t sublayer, auto& shader, const auto& subject) {
+ context.draw({
+ depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite),
+ stencilModeForClipping(tile.clip),
+ colorModeForRenderPass(),
+ shader,
+ FillPatternUniforms::values(
+ tile.translatedMatrix(properties.fillTranslate.value,
+ properties.fillTranslateAnchor.value,
+ state),
+ properties.fillOpacity.value,
+ context.viewport.getCurrentValue().size,
+ *imagePosA,
+ *imagePosB,
+ properties.fillPattern.value,
+ tile.id,
+ state
+ ),
+ subject
+ });
+ };
+
+ draw(0,
+ parameters.shaders.fillPattern,
+ gl::Segmented<gl::Triangles>(
+ *bucket.vertexBuffer,
+ *bucket.triangleIndexBuffer,
+ bucket.triangleSegments));
+
+ if (!properties.fillAntialias.value || !properties.fillOutlineColor.isUndefined()) {
+ return;
}
- }
-
- // Because we're drawing top-to-bottom, and we update the stencil mask
- // below, we have to draw the outline first (!)
- if (fringeline && pass == RenderPass::Translucent) {
- context.program = outlineShader.getID();
- outlineShader.u_matrix = vertexMatrix;
- outlineShader.u_outline_color = fillColor;
- outlineShader.u_opacity = opacity;
+ draw(2,
+ parameters.shaders.fillOutlinePattern,
+ gl::Segmented<gl::Lines>(
+ *bucket.vertexBuffer,
+ *bucket.lineIndexBuffer,
+ bucket.lineSegments,
+ 2.0f));
+ } else {
+ auto draw = [&] (uint8_t sublayer, auto& shader, Color outlineColor, const auto& subject) {
+ context.draw({
+ depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite),
+ stencilModeForClipping(tile.clip),
+ colorModeForRenderPass(),
+ shader,
+ FillColorUniforms::values(
+ tile.translatedMatrix(properties.fillTranslate.value,
+ properties.fillTranslateAnchor.value,
+ state),
+ properties.fillOpacity.value,
+ properties.fillColor.value,
+ outlineColor,
+ context.viewport.getCurrentValue().size
+ ),
+ subject
+ });
+ };
+
+ if (properties.fillAntialias.value && !properties.fillOutlineColor.isUndefined() && pass == RenderPass::Translucent) {
+ draw(2,
+ parameters.shaders.fillOutline,
+ properties.fillOutlineColor.value,
+ gl::Segmented<gl::Lines>(
+ *bucket.vertexBuffer,
+ *bucket.lineIndexBuffer,
+ bucket.lineSegments,
+ 2.0f));
+ }
- // Draw the entire line
- outlineShader.u_world = worldSize;
+ // Only draw the fill when it's opaque and we're drawing opaque fragments,
+ // or when it's translucent and we're drawing translucent fragments.
+ if ((properties.fillColor.value.a >= 1.0f && properties.fillOpacity.value >= 1.0f) == (pass == RenderPass::Opaque)) {
+ draw(1,
+ parameters.shaders.fill,
+ properties.fillOutlineColor.value,
+ gl::Segmented<gl::Triangles>(
+ *bucket.vertexBuffer,
+ *bucket.triangleIndexBuffer,
+ bucket.triangleSegments));
+ }
- setDepthSublayer(2);
- bucket.drawVertices(outlineShader, context, paintMode());
+ if (properties.fillAntialias.value && properties.fillOutlineColor.isUndefined() && pass == RenderPass::Translucent) {
+ draw(2,
+ parameters.shaders.fillOutline,
+ properties.fillColor.value,
+ gl::Segmented<gl::Lines>(
+ *bucket.vertexBuffer,
+ *bucket.lineIndexBuffer,
+ bucket.lineSegments,
+ 2.0f));
+ }
}
}