diff options
Diffstat (limited to 'src/mbgl/renderer/painter_fill.cpp')
-rw-r--r-- | src/mbgl/renderer/painter_fill.cpp | 243 |
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)); + } } } |