summaryrefslogtreecommitdiff
path: root/src/mbgl/renderer/buckets/hillshade_bucket.cpp
blob: 08f941f990816e67390df7a0f64c86701606f857 (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/buckets/hillshade_bucket.hpp>
#include <mbgl/renderer/layers/render_hillshade_layer.hpp>
#include <mbgl/programs/hillshade_program.hpp>
#include <mbgl/programs/hillshade_prepare_program.hpp>
#include <mbgl/gfx/context.hpp>

namespace mbgl {

using namespace style;

HillshadeBucket::HillshadeBucket(PremultipliedImage&& image_, Tileset::DEMEncoding encoding)
    : demdata(image_, encoding) {
}

HillshadeBucket::HillshadeBucket(DEMData&& demdata_)
    : demdata(std::move(demdata_)) {
}

HillshadeBucket::~HillshadeBucket() = default;

const DEMData& HillshadeBucket::getDEMData() const {
    return demdata;
}

DEMData& HillshadeBucket::getDEMData() {
    return demdata;
}

void HillshadeBucket::upload(gfx::UploadPass& uploadPass) {
    if (!hasData()) {
        return;
    }


    const PremultipliedImage* image = demdata.getImage();
    dem = uploadPass.createTexture(*image);

    if (!segments.empty()) {
        vertexBuffer = uploadPass.createVertexBuffer(std::move(vertices));
        indexBuffer = uploadPass.createIndexBuffer(std::move(indices));
    }
    uploaded = true;
}

void HillshadeBucket::clear() {
    vertexBuffer = {};
    indexBuffer = {};
    segments.clear();
    vertices.clear();
    indices.clear();

    uploaded = false;
}

void HillshadeBucket::setMask(TileMask&& mask_) {
    if (mask == mask_) {
        return;
    }

    mask = std::move(mask_);
    clear();

    if (mask == TileMask{ { 0, 0, 0 } }) {
        // We want to render the full tile, and keeping the segments/vertices/indices empty means
        // using the global shared buffers for covering the entire tile.
        return;
    }

    // Create a new segment so that we will upload (empty) buffers even when there is nothing to
    // draw for this tile.
    segments.emplace_back(0, 0);

    constexpr const uint16_t vertexLength = 4;

    // Create the vertex buffer for the specified tile mask.
    for (const auto& id : mask) {
        // Create a quad for every masked tile.
        const int32_t vertexExtent = util::EXTENT >> id.z;

        const Point<int16_t> tlVertex = { static_cast<int16_t>(id.x * vertexExtent),
                                          static_cast<int16_t>(id.y * vertexExtent) };
        const Point<int16_t> brVertex = { static_cast<int16_t>(tlVertex.x + vertexExtent),
                                          static_cast<int16_t>(tlVertex.y + vertexExtent) };

        if (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.elements(), indices.elements());
        }

        vertices.emplace_back(
            HillshadeProgram::layoutVertex({ tlVertex.x, tlVertex.y }, { static_cast<uint16_t>(tlVertex.x), static_cast<uint16_t>(tlVertex.y) }));
        vertices.emplace_back(
            HillshadeProgram::layoutVertex({ brVertex.x, tlVertex.y }, { static_cast<uint16_t>(brVertex.x), static_cast<uint16_t>(tlVertex.y) }));
        vertices.emplace_back(
            HillshadeProgram::layoutVertex({ tlVertex.x, brVertex.y }, { static_cast<uint16_t>(tlVertex.x), static_cast<uint16_t>(brVertex.y) }));
        vertices.emplace_back(
            HillshadeProgram::layoutVertex({ brVertex.x, brVertex.y }, { static_cast<uint16_t>(brVertex.x), static_cast<uint16_t>(brVertex.y) }));

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

        // 0, 1, 2
        // 1, 2, 3
        indices.emplace_back(offset, offset + 1, offset + 2);
        indices.emplace_back(offset + 1, offset + 2, offset + 3);

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

bool HillshadeBucket::hasData() const {
    return demdata.getImage()->valid();
}

bool HillshadeBucket::supportsLayer(const style::Layer::Impl& impl) const {
    return style::HillshadeLayer::Impl::staticTypeInfo() == impl.getTypeInfo();
}


} // namespace mbgl