summaryrefslogtreecommitdiff
path: root/src/mbgl/sprite/sprite_atlas.hpp
blob: 1dbef86f7e336ecbe3a3eea5450d05ad85e1c3e9 (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
#pragma once

#include <mbgl/gl/texture.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/util/rect.hpp>
#include <mbgl/style/image.hpp>

#include <mapbox/shelf-pack.hpp>

#include <string>
#include <set>
#include <unordered_map>
#include <array>
#include <memory>

namespace mbgl {

namespace gl {
class Context;
} // namespace gl

class SpriteAtlasElement {
public:
    SpriteAtlasElement(const mapbox::Bin&, const style::Image::Impl&);

    bool sdf;
    float pixelRatio;
    Rect<uint16_t> textureRect;

    std::array<uint16_t, 2> tl() const {
        return {{
            textureRect.x,
            textureRect.y
        }};
    }

    std::array<uint16_t, 2> br() const {
        return {{
            static_cast<uint16_t>(textureRect.x + textureRect.w),
            static_cast<uint16_t>(textureRect.y + textureRect.h)
        }};
    }

    std::array<float, 2> displaySize() const {
        return {{
            textureRect.w / pixelRatio,
            textureRect.h / pixelRatio,
        }};
    }
};

using IconMap = std::unordered_map<std::string, SpriteAtlasElement>;
using IconDependencies = std::set<std::string>;

class IconRequestor {
public:
    virtual ~IconRequestor() = default;
    virtual void onIconsAvailable(IconMap) = 0;
};

class SpriteAtlas : public util::noncopyable {
public:
    SpriteAtlas();
    ~SpriteAtlas();

    void onSpriteLoaded();

    bool isLoaded() const {
        return loaded;
    }

    void dumpDebugLogs() const;

    const style::Image::Impl* getImage(const std::string&) const;

    void addImage(Immutable<style::Image::Impl>);
    void updateImage(Immutable<style::Image::Impl>);
    void removeImage(const std::string&);

    void getIcons(IconRequestor&, IconDependencies);
    void removeRequestor(IconRequestor&);

    // Ensure that the atlas contains the named image suitable for rendering as an icon, and
    // return its metrics. The image will be padded on each side with a one pixel wide transparent
    // strip, but the returned metrics are exclusive of this padding.
    optional<SpriteAtlasElement> getIcon(const std::string& name);

    // Ensure that the atlas contains the named image suitable for rendering as an pattern, and
    // return its metrics. The image will be padded on each side with a one pixel wide copy of
    // pixels from the opposite side, but the returned metrics are exclusive of this padding.
    optional<SpriteAtlasElement> getPattern(const std::string& name);

    // Binds the atlas texture to the GPU, and uploads data if it is out of date.
    void bind(bool linear, gl::Context&, gl::TextureUnit unit);

    // Uploads the texture to the GPU to be available when we need it. This is a lazy operation;
    // the texture is only bound when the data is out of date (=dirty).
    void upload(gl::Context&, gl::TextureUnit unit);

    Size getPixelSize() const;

    // Only for use in tests.
    const PremultipliedImage& getAtlasImage() const {
        return image;
    }

private:
    bool loaded = false;

    struct Entry {
        Immutable<style::Image::Impl> image;

        // One sprite image might be used as both an icon image and a pattern image. If so,
        // it must have two distinct entries in the texture. The one for the icon image has
        // a single pixel transparent border, and the one for the pattern image has a single
        // pixel border wrapped from the opposite side.
        mapbox::Bin* iconBin = nullptr;
        mapbox::Bin* patternBin = nullptr;
    };

    optional<SpriteAtlasElement> getImage(const std::string& name, mapbox::Bin* Entry::*bin);
    void copy(const Entry&, mapbox::Bin* Entry::*bin);
    
    IconMap buildIconMap();

    std::unordered_map<std::string, Entry> entries;
    mapbox::ShelfPack shelfPack;
    PremultipliedImage image;
    mbgl::optional<gl::Texture> texture;
    bool dirty = true;
    
    std::set<IconRequestor*> requestors;
    IconMap icons;
};

} // namespace mbgl