#pragma once #include #include #include #include #include namespace mbgl { namespace gl { template class Attribute { public: using Type = T[N]; class State { public: explicit State(AttributeLocation location_) : location(location_) {} AttributeLocation location; static constexpr std::size_t count = N; static constexpr DataType type = DataTypeOf::value; }; }; #define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \ struct name_ : ::mbgl::gl::Attribute { static constexpr auto name = #name_; } namespace detail { // Attribute binding requires member offsets. The only standard way to // obtain an offset is the offsetof macro. The offsetof macro has defined // behavior only for standard layout types. That rules out std::tuple and // any other solution that relies on chained inheritance. Manually implemented // variadic specialization looks like the only solution. Fortunately, we // only use a maximum of five attributes. template class Vertex; template class Vertex { public: typename A1::Type a1; using VertexType = Vertex; static const std::size_t attributeOffsets[1]; }; template class Vertex { public: typename A1::Type a1; typename A2::Type a2; using VertexType = Vertex; static const std::size_t attributeOffsets[2]; }; template class Vertex { public: typename A1::Type a1; typename A2::Type a2; typename A3::Type a3; using VertexType = Vertex; static const std::size_t attributeOffsets[3]; }; template class Vertex { public: typename A1::Type a1; typename A2::Type a2; typename A3::Type a3; typename A4::Type a4; using VertexType = Vertex; static const std::size_t attributeOffsets[4]; }; template class Vertex { public: typename A1::Type a1; typename A2::Type a2; typename A3::Type a3; typename A4::Type a4; typename A5::Type a5; using VertexType = Vertex; static const std::size_t attributeOffsets[5]; }; template const std::size_t Vertex::attributeOffsets[1] = { offsetof(VertexType, a1) }; template const std::size_t Vertex::attributeOffsets[2] = { offsetof(VertexType, a1), offsetof(VertexType, a2) }; template const std::size_t Vertex::attributeOffsets[3] = { offsetof(VertexType, a1), offsetof(VertexType, a2), offsetof(VertexType, a3) }; template const std::size_t Vertex::attributeOffsets[4] = { offsetof(VertexType, a1), offsetof(VertexType, a2), offsetof(VertexType, a3), offsetof(VertexType, a4) }; template const std::size_t Vertex::attributeOffsets[5] = { offsetof(VertexType, a1), offsetof(VertexType, a2), offsetof(VertexType, a3), offsetof(VertexType, a4), offsetof(VertexType, a5) }; } // namespace detail AttributeLocation bindAttributeLocation(ProgramID, AttributeLocation, const char * name); void bindAttribute(AttributeLocation location, std::size_t count, DataType type, std::size_t vertexSize, std::size_t vertexOffset, std::size_t attributeOffset); template class Attributes { public: using State = IndexedTuple, TypeList>; using Vertex = detail::Vertex; template static constexpr std::size_t Index = TypeIndex::value; static State state(const ProgramID& id) { return State { typename As::State(bindAttributeLocation(id, Index, As::name))... }; } static std::function binder(const State& state) { return [&state] (std::size_t vertexOffset) { util::ignore({ (bindAttribute(state.template get().location, state.template get().count, state.template get().type, sizeof(Vertex), vertexOffset, Vertex::attributeOffsets[Index]), 0)... }); }; } }; } // namespace gl } // namespace mbgl