summaryrefslogtreecommitdiff
path: root/src/renderer/painter_fill.cpp
blob: f2759ffd61ed06fef39673074b68e6ceac6daf5c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/map/sprite.hpp>
#include <mbgl/geometry/sprite_atlas.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/mat3.hpp>

using namespace mbgl;

void Painter::renderFill(FillBucket& bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix) {
    // Abort early.
    if (!bucket.hasData()) return;

    const FillProperties &properties = layer_desc->getProperties<FillProperties>();
    mat4 vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor);

    Color fill_color = properties.fill_color;
    fill_color[0] *= properties.opacity;
    fill_color[1] *= properties.opacity;
    fill_color[2] *= properties.opacity;
    fill_color[3] *= properties.opacity;

    Color stroke_color = properties.stroke_color;
    if (stroke_color[3] < 0) {
        stroke_color = fill_color;
    } else {
        stroke_color[0] *= properties.opacity;
        stroke_color[1] *= properties.opacity;
        stroke_color[2] *= properties.opacity;
        stroke_color[3] *= properties.opacity;
    }

    const bool pattern = properties.image.size();

    bool outline = properties.antialias && !pattern && properties.stroke_color != properties.fill_color;
    bool fringeline = properties.antialias && !pattern && 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 && pass == RenderPass::Translucent) {
        useProgram(outlineShader->program);
        outlineShader->u_matrix = vtxMatrix;
        lineWidth(2.0f); // This is always fixed and does not depend on the pixelRatio!

        outlineShader->u_color = stroke_color;

        // Draw the entire line
        outlineShader->u_world = {{
            static_cast<float>(state.getFramebufferWidth()),
            static_cast<float>(state.getFramebufferHeight())
        }};
        depthRange(strata, 1.0f);
        bucket.drawVertices(*outlineShader);
    }

    if (pattern) {
        // Image fill.
        if (pass == RenderPass::Translucent) {
            const SpriteAtlasPosition pos = spriteAtlas.getPosition(properties.image, true);
            const float mix = std::fmod(float(state.getZoom()), 1.0f);
            const float factor = 8.0 / std::pow(2, state.getIntegerZoom() - id.z);

            mat3 patternMatrix;
            matrix::identity(patternMatrix);
            matrix::scale(patternMatrix, patternMatrix, 1.0f / (pos.size[0] * factor), 1.0f / (pos.size[1] * factor));

            useProgram(patternShader->program);
            patternShader->u_matrix = vtxMatrix;
            patternShader->u_pattern_tl = pos.tl;
            patternShader->u_pattern_br = pos.br;
            patternShader->u_opacity = properties.opacity;
            patternShader->u_image = 0;
            patternShader->u_mix = mix;
            patternShader->u_patternmatrix = patternMatrix;

            glActiveTexture(GL_TEXTURE0);
            spriteAtlas.bind(true);

            // Draw the actual triangles into the color & stencil buffer.
            depthRange(strata, 1.0f);
            bucket.drawElements(*patternShader);
        }
    }
    else {
        // No image fill.
        if ((fill_color[3] >= 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.
            useProgram(plainShader->program);
            plainShader->u_matrix = vtxMatrix;
            plainShader->u_color = fill_color;

            // Draw the actual triangles into the color & stencil buffer.
            depthRange(strata + strata_epsilon, 1.0f);
            bucket.drawElements(*plainShader);
        }
    }

    // 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) {
        useProgram(outlineShader->program);
        outlineShader->u_matrix = vtxMatrix;
        lineWidth(2.0f); // This is always fixed and does not depend on the pixelRatio!

        outlineShader->u_color = fill_color;

        // Draw the entire line
        outlineShader->u_world = {{
            static_cast<float>(state.getFramebufferWidth()),
            static_cast<float>(state.getFramebufferHeight())
        }};

        depthRange(strata + strata_epsilon, 1.0f);
        bucket.drawVertices(*outlineShader);
    }
}