summaryrefslogtreecommitdiff
path: root/src/mbgl/gl/attribute.hpp
blob: dc112c1ad88dd96b01082bf8ca28ae64f390b697 (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
#pragma once

#include <mbgl/gfx/attribute.hpp>
#include <mbgl/gl/types.hpp>
#include <mbgl/gfx/vertex_buffer.hpp>
#include <mbgl/util/ignore.hpp>
#include <mbgl/util/indexed_tuple.hpp>
#include <mbgl/util/optional.hpp>

#include <cstddef>
#include <vector>
#include <set>
#include <functional>
#include <string>
#include <array>
#include <limits>

namespace mbgl {
namespace gl {

class AttributeBinding {
public:
    gfx::AttributeDescriptor attribute;
    uint8_t vertexStride;
    const gfx::VertexBufferResource* vertexBufferResource;
    uint32_t vertexOffset;

    friend bool operator==(const AttributeBinding& lhs, const AttributeBinding& rhs) {
        return lhs.attribute == rhs.attribute &&
               lhs.vertexStride == rhs.vertexStride &&
               lhs.vertexBufferResource == rhs.vertexBufferResource &&
               lhs.vertexOffset == rhs.vertexOffset;
    }
};

using AttributeBindingArray = std::vector<optional<AttributeBinding>>;

    /*
        Create a binding for this attribute.  The `attributeSize` parameter may be used to
        override the number of components available in the buffer for each vertex.  Thus,
        a buffer with only one float for each vertex can be bound to a `vec2` attribute
    */
template <std::size_t I, typename Vertex>
AttributeBinding attributeBinding(const gfx::VertexBuffer<Vertex>& buffer) {
    static_assert(I < gfx::VertexDescriptorOf<Vertex>::data.count, "vertex attribute index out of range");
    return {
        gfx::VertexDescriptorOf<Vertex>::data.attributes[I],
        gfx::VertexDescriptorOf<Vertex>::data.stride,
        buffer.resource.get(),
        0,
    };
}

optional<AttributeBinding> offsetAttributeBinding(const optional<AttributeBinding>& binding, std::size_t vertexOffset);

class Context;
void bindAttributeLocation(Context&, ProgramID, AttributeLocation, const char * name);
std::set<std::string> getActiveAttributes(ProgramID);

template <class>
class Attributes;

template <class... As>
class Attributes<TypeList<As...>> final {
public:
    using Types = TypeList<As...>;
    using Locations = IndexedTuple<
        TypeList<As...>,
        TypeList<ExpandToType<As, optional<AttributeLocation>>...>>;
    using Bindings = IndexedTuple<
        TypeList<As...>,
        TypeList<ExpandToType<As, optional<AttributeBinding>>...>>;
    using NamedLocations = std::vector<std::pair<const std::string, AttributeLocation>>;

    static Locations bindLocations(Context& context, const ProgramID& id) {
        std::set<std::string> activeAttributes = getActiveAttributes(id);

        AttributeLocation location = 0;
        auto maybeBindLocation = [&](const char* name) -> optional<AttributeLocation> {
            if (activeAttributes.count(name)) {
                bindAttributeLocation(context, id, location, name);
                return location++;
            } else {
                return {};
            }
        };

        return Locations { maybeBindLocation(As::name())... };
    }

    template <class Program>
    static Locations loadNamedLocations(const Program& program) {
        return Locations{ program.attributeLocation(As::name())... };
    }

    static NamedLocations getNamedLocations(const Locations& locations) {
        NamedLocations result;

        auto maybeAddLocation = [&] (const std::string& name, const optional<AttributeLocation>& location) {
            if (location) {
                result.emplace_back(name, *location);
            }
        };

        util::ignore({ (maybeAddLocation(As::name(), locations.template get<As>()), 0)... });

        return result;
    }

    static Bindings bindings(const gfx::VertexBuffer<gfx::Vertex<Types>>& buffer) {
        return Bindings { attributeBinding<TypeIndex<As, As...>::value>(buffer)... };
    }

    static Bindings offsetBindings(const Bindings& bindings, std::size_t vertexOffset) {
        return Bindings { offsetAttributeBinding(bindings.template get<As>(), vertexOffset)... };
    }

    static AttributeBindingArray toBindingArray(const Locations& locations, const Bindings& bindings) {
        AttributeBindingArray result;
        result.resize(sizeof...(As));

        auto maybeAddBinding = [&] (const optional<AttributeLocation>& location,
                                    const optional<AttributeBinding>& binding) {
            if (location) {
                result.at(*location) = binding;
            }
        };

        util::ignore({ (maybeAddBinding(locations.template get<As>(), bindings.template get<As>()), 0)... });

        return result;
    }

    static uint32_t activeBindingCount(const Bindings& bindings) {
        uint32_t result = 0;
        util::ignore({ ((result += bool(bindings.template get<As>())), 0)... });
        return result;
    }
};

} // namespace gl
} // namespace mbgl