summaryrefslogtreecommitdiff
path: root/src/mbgl/renderer/painter_fill.cpp
blob: d98cb2b57cec8e5834c78204c3f835d92ee8f19a (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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/paint_parameters.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/programs/programs.hpp>
#include <mbgl/programs/fill_program.hpp>
#include <mbgl/util/convert.hpp>

namespace mbgl {

using namespace style;

void Painter::renderFill(PaintParameters& parameters,
                         FillBucket& bucket,
                         const FillLayer& layer,
                         const RenderTile& tile) {
    const FillPaintProperties::Evaluated& properties = layer.impl->paint.evaluated;

    if (!properties.get<FillPattern>().from.empty()) {
        if (pass != RenderPass::Translucent) {
            return;
        }

        optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition(
            properties.get<FillPattern>().from, SpritePatternMode::Repeating);
        optional<SpriteAtlasPosition> imagePosB = spriteAtlas->getPosition(
            properties.get<FillPattern>().to, SpritePatternMode::Repeating);

        if (!imagePosA || !imagePosB) {
            return;
        }

        spriteAtlas->bind(true, context, 0);

        auto draw = [&] (uint8_t sublayer,
                         auto& program,
                         const auto& drawMode,
                         const auto& indexBuffer,
                         const auto& segments) {
            program.draw(
                context,
                drawMode,
                depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite),
                stencilModeForClipping(tile.clip),
                colorModeForRenderPass(),
                FillPatternUniforms::values(
                    tile.translatedMatrix(properties.get<FillTranslate>(),
                                          properties.get<FillTranslateAnchor>(),
                                          state),
                    context.viewport.getCurrentValue().size,
                    *imagePosA,
                    *imagePosB,
                    properties.get<FillPattern>(),
                    tile.id,
                    state
                ),
                *bucket.vertexBuffer,
                indexBuffer,
                segments,
                bucket.paintPropertyBinders.at(layer.getID()),
                properties,
                state.getZoom()
            );
        };

        draw(0,
             parameters.programs.fillPattern,
             gl::Triangles(),
             *bucket.triangleIndexBuffer,
             bucket.triangleSegments);

        if (!properties.get<FillAntialias>() || !layer.impl->paint.unevaluated.get<FillOutlineColor>().isUndefined()) {
            return;
        }

        draw(2,
             parameters.programs.fillOutlinePattern,
             gl::Lines { 2.0f },
             *bucket.lineIndexBuffer,
             bucket.lineSegments);
    } else {
        auto draw = [&] (uint8_t sublayer,
                         auto& program,
                         const auto& drawMode,
                         const auto& indexBuffer,
                         const auto& segments) {
            program.draw(
                context,
                drawMode,
                depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite),
                stencilModeForClipping(tile.clip),
                colorModeForRenderPass(),
                FillProgram::UniformValues {
                    uniforms::u_matrix::Value{
                        tile.translatedMatrix(properties.get<FillTranslate>(),
                                              properties.get<FillTranslateAnchor>(),
                                              state)
                    },
                    uniforms::u_world::Value{ context.viewport.getCurrentValue().size },
                },
                *bucket.vertexBuffer,
                indexBuffer,
                segments,
                bucket.paintPropertyBinders.at(layer.getID()),
                properties,
                state.getZoom()
            );
        };

        if (properties.get<FillAntialias>() && !layer.impl->paint.unevaluated.get<FillOutlineColor>().isUndefined() && pass == RenderPass::Translucent) {
            draw(2,
                 parameters.programs.fillOutline,
                 gl::Lines { 2.0f },
                 *bucket.lineIndexBuffer,
                 bucket.lineSegments);
        }

        // 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.get<FillColor>().constantOr(Color()).a >= 1.0f
          && properties.get<FillOpacity>().constantOr(0) >= 1.0f) == (pass == RenderPass::Opaque)) {
            draw(1,
                 parameters.programs.fill,
                 gl::Triangles(),
                 *bucket.triangleIndexBuffer,
                 bucket.triangleSegments);
        }

        if (properties.get<FillAntialias>() && layer.impl->paint.unevaluated.get<FillOutlineColor>().isUndefined() && pass == RenderPass::Translucent) {
            draw(2,
                 parameters.programs.fillOutline,
                 gl::Lines { 2.0f },
                 *bucket.lineIndexBuffer,
                 bucket.lineSegments);
        }
    }
}

} // namespace mbgl