summaryrefslogtreecommitdiff
path: root/src/mbgl/style/style_layer.hpp
blob: d44b2ce7ccb8e0eca8b4bdc16159c8103e8afe41 (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
#ifndef MBGL_STYLE_STYLE_LAYER
#define MBGL_STYLE_STYLE_LAYER

#include <mbgl/style/class_dictionary.hpp>
#include <mbgl/style/class_properties.hpp>
#include <mbgl/style/applied_class_properties.hpp>
#include <mbgl/style/zoom_history.hpp>
#include <mbgl/style/property_evaluator.hpp>

#include <mbgl/renderer/render_pass.hpp>

#include <mbgl/util/ptr.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/interpolate.hpp>

#include <vector>
#include <string>
#include <map>
#include <set>

namespace mbgl {

class StyleBucket;

class StyleLayer : public util::noncopyable {
public:
    static std::unique_ptr<StyleLayer> create(StyleLayerType);

    virtual ~StyleLayer() = default;

    // Determines whether this layer is the background layer.
    bool isBackground() const;

    // Checks whether this layer needs to be rendered in the given render pass.
    bool hasRenderPass(RenderPass) const;

    // Updates the StyleProperties information in this layer by evaluating all
    // pending transitions and applied classes in order.
    void updateProperties(float z, const TimePoint& now, ZoomHistory &zoomHistory);

    // Sets the list of classes and creates transitions to the currently applied values.
    void setClasses(const std::vector<std::string> &class_names, const TimePoint& now,
                    const PropertyTransition &defaultTransition);

    bool hasTransitions() const;

public:
    // The name of this layer.
    std::string id;

    StyleLayerType type = StyleLayerType::Unknown;

    // Bucket information, telling the renderer how to generate the geometries
    // for this layer (feature property filters, tessellation instructions, ...).
    util::ptr<StyleBucket> bucket;

    // Contains all style classes that can be applied to this layer.
    std::map<ClassID, ClassProperties> styles;

protected:
    // TODO: extract
    template <typename T>
    void applyStyleProperty(PropertyKey key, T& target, const float z, const TimePoint& now, const ZoomHistory& zoomHistory) {
        auto it = appliedStyle.find(key);
        if (it != appliedStyle.end()) {
            AppliedClassPropertyValues &applied = it->second;
            // Iterate through all properties that we need to apply in order.
            const PropertyEvaluator<T> evaluator(z, zoomHistory);
            for (auto& property : applied.propertyValues) {
                if (now >= property.begin) {
                    // We overwrite the current property with the new value.
                    target = mapbox::util::apply_visitor(evaluator, property.value);
                } else {
                    // Do not apply this property because its transition hasn't begun yet.
                }
            }
        }
    }

    template <typename T>
    void applyTransitionedStyleProperty(PropertyKey key, T& target, const float z, const TimePoint& now, const ZoomHistory& zoomHistory) {
        auto it = appliedStyle.find(key);
        if (it != appliedStyle.end()) {
            AppliedClassPropertyValues &applied = it->second;
            // Iterate through all properties that we need to apply in order.
            const PropertyEvaluator<T> evaluator(z, zoomHistory);
            for (auto& property : applied.propertyValues) {
                if (now >= property.end) {
                    // We overwrite the current property with the new value.
                    target = mapbox::util::apply_visitor(evaluator, property.value);
                } else if (now >= property.begin) {
                    // We overwrite the current property partially with the new value.
                    float progress = std::chrono::duration<float>(now - property.begin) / (property.end - property.begin);
                    target = util::interpolate(target, mapbox::util::apply_visitor(evaluator, property.value), progress);
                    hasPendingTransitions = true;
                } else {
                    // Do not apply this property because its transition hasn't begun yet.
                }
            }
        }
    }

private:
    // Applies all properties from a class, if they haven't been applied already.
    void applyClassProperties(ClassID class_id, std::set<PropertyKey> &already_applied,
                              const TimePoint& now, const PropertyTransition &defaultTransition);

    // Sets the properties of this object by evaluating all pending transitions and
    // aplied classes in order.
    virtual RenderPass applyStyleProperties(float z, const TimePoint& now, const ZoomHistory&) = 0;

    // Removes all expired style transitions.
    void cleanupAppliedStyleProperties(const TimePoint& now);

    // For every property, stores a list of applied property values, with
    // optional transition times.
    std::map<PropertyKey, AppliedClassPropertyValues> appliedStyle;

    // Stores what render passes this layer is currently enabled for. This depends on the
    // evaluated StyleProperties object and is updated accordingly.
    RenderPass passes = RenderPass::None;

    // Stores whether there are pending transitions to be done on each update.
    bool hasPendingTransitions = false;
};

}

#endif