summaryrefslogtreecommitdiff
path: root/src/mbgl/renderer/buckets/circle_bucket.cpp
blob: 20c40eb0cb3a89e45321802d268141a2c23e9e67 (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
#include <mbgl/renderer/buckets/circle_bucket.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/programs/circle_program.hpp>
#include <mbgl/style/layers/circle_layer_impl.hpp>
#include <mbgl/renderer/layers/render_circle_layer.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/math.hpp>

namespace mbgl {

using namespace style;

CircleBucket::CircleBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers)
    : Bucket(LayerType::Circle),
      mode(parameters.mode) {
    for (const auto& layer : layers) {
        paintPropertyBinders.emplace(
            std::piecewise_construct,
            std::forward_as_tuple(layer->getID()),
            std::forward_as_tuple(
                layer->as<RenderCircleLayer>()->evaluated,
                parameters.tileID.overscaledZ));
        if (layer->as<RenderCircleLayer>()->evaluated.isFeatureStateDependent()) {
            stateDependentLayers.emplace(layer->getID());
        }
    }
}

void CircleBucket::upload(gl::Context& context) {
    if (!vertexBuffer) {
        vertexBuffer = context.createVertexBuffer(std::move(vertices));
        indexBuffer = context.createIndexBuffer(std::move(triangles));
    }
    for (auto& pair : paintPropertyBinders) {
        pair.second.upload(context);
    }

    uploaded = true;
}

bool CircleBucket::hasData() const {
    return !segments.empty();
}

void CircleBucket::addFeature(const GeometryTileFeature& feature,
                                 const GeometryCollection& geometry,
                                 size_t featureIndex,
                                 const ImagePositions&,
                                 const PatternLayerMap&) {
    constexpr const uint16_t vertexLength = 4;

    for (auto& circle : geometry) {
        for(auto& point : circle) {
            auto x = point.x;
            auto y = point.y;

            // Do not include points that are outside the tile boundaries.
            // Include all points in Still mode. You need to include points from
            // neighbouring tiles so that they are not clipped at tile boundaries.
            if ((mode == MapMode::Continuous) &&
                (x < 0 || x >= util::EXTENT || y < 0 || y >= util::EXTENT)) continue;

            if (segments.empty() || segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) {
                // Move to a new segments because the old one can't hold the geometry.
                segments.emplace_back(vertices.vertexSize(), triangles.indexSize());
            }

            // this geometry will be of the Point type, and we'll derive
            // two triangles from it.
            //
            // ┌─────────┐
            // │ 4     3 │
            // │         │
            // │ 1     2 │
            // └─────────┘
            //
            vertices.emplace_back(CircleProgram::vertex(point, -1, -1)); // 1
            vertices.emplace_back(CircleProgram::vertex(point,  1, -1)); // 2
            vertices.emplace_back(CircleProgram::vertex(point,  1,  1)); // 3
            vertices.emplace_back(CircleProgram::vertex(point, -1,  1)); // 4

            auto& segment = segments.back();
            assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max());
            uint16_t index = segment.vertexLength;

            // 1, 2, 3
            // 1, 4, 3
            triangles.emplace_back(index, index + 1, index + 2);
            triangles.emplace_back(index, index + 3, index + 2);

            segment.vertexLength += vertexLength;
            segment.indexLength += 6;
        }
    }

    for (auto& pair : paintPropertyBinders) {
        pair.second.populateVertexVectors(feature, featureIndex, vertices.vertexSize(), {}, {});
    }
}

void CircleBucket::setFeatureState(const GeometryTileData* tileData,
                        const std::string& sourceLayer,
                        const FeatureStates& featureStates) {
    if (featureStates.empty() /*|| stateDependentLayers.empty()*/) { return; }

    auto sourceLayerData = tileData->getLayer(sourceLayer);
    if (sourceLayerData) {
        for (auto& pair : paintPropertyBinders) {
            if (stateDependentLayers.count(pair.first) > 0) {
                if(pair.second.updateVertexVectors(featureStates,  *sourceLayerData)) {
                    //Only toggle uploaded if needed.
                    uploaded = false;
                }
            }
        }
    }
}
template <class Property>
static float get(const RenderCircleLayer& layer, const std::map<std::string, CircleProgram::PaintPropertyBinders>& paintPropertyBinders) {
    auto it = paintPropertyBinders.find(layer.getID());
    if (it == paintPropertyBinders.end() || !it->second.statistics<Property>().max()) {
        return layer.evaluated.get<Property>().constantOr(Property::defaultValue());
    } else {
        return *it->second.statistics<Property>().max();
    }
}

float CircleBucket::getQueryRadius(const RenderLayer& layer) const {
    if (!layer.is<RenderCircleLayer>()) {
        return 0;
    }

    auto circleLayer = layer.as<RenderCircleLayer>();

    float radius = get<CircleRadius>(*circleLayer, paintPropertyBinders);
    float stroke = get<CircleStrokeWidth>(*circleLayer, paintPropertyBinders);
    auto translate = circleLayer->evaluated.get<CircleTranslate>();
    return radius + stroke + util::length(translate[0], translate[1]);
}

} // namespace mbgl