#pragma once #include #include #include #include #include #include #include #include #include namespace mbgl { namespace gl { class DisabledAttribute { public: void bind(Context&, AttributeLocation, std::size_t vertexOffset) const; friend bool operator==(const DisabledAttribute&, const DisabledAttribute&) { return true; } }; template class AttributeBinding { public: AttributeBinding(BufferID vertexBuffer_, std::size_t vertexSize_, std::size_t attributeOffset_, std::size_t attributeSize_ = N) : vertexBuffer(vertexBuffer_), vertexSize(vertexSize_), attributeOffset(attributeOffset_), attributeSize(attributeSize_) {} void bind(Context&, AttributeLocation, std::size_t vertexOffset) const; friend bool operator==(const AttributeBinding& lhs, const AttributeBinding& rhs) { return lhs.vertexBuffer == rhs.vertexBuffer && lhs.vertexSize == rhs.vertexSize && lhs.attributeOffset == rhs.attributeOffset && lhs.attributeSize == rhs.attributeSize; } private: BufferID vertexBuffer; std::size_t vertexSize; std::size_t attributeOffset; std::size_t attributeSize; }; /* gl::Attribute manages the binding of a vertex buffer to a GL program attribute. - T is the underlying primitive type (exposed as Attribute::ValueType) - N is the number of components in the attribute declared in the shader (exposed as Attribute::Dimensions) */ template class Attribute { public: using ValueType = T; static constexpr size_t Dimensions = N; using Value = std::array; using Location = AttributeLocation; using Binding = variant< DisabledAttribute, 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 static Binding binding(const VertexBuffer& buffer, std::size_t attributeIndex, std::size_t attributeSize = N) { static_assert(std::is_standard_layout::value, "vertex type must use standard layout"); return AttributeBinding { buffer.buffer, sizeof(Vertex), Vertex::attributeOffsets[attributeIndex], attributeSize }; } static void bind(Context& context, const Location& location, Binding& oldBinding, const Binding& newBinding, std::size_t vertexOffset) { if (oldBinding == newBinding) { return; } Binding::visit(newBinding, [&] (const auto& binding) { binding.bind(context, location, vertexOffset); }); oldBinding = newBinding; } }; #define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \ struct name_ { \ static auto name() { return #name_; } \ using Type = ::mbgl::gl::Attribute; \ } 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: using VertexType = Vertex<>; }; template class Vertex { public: typename A1::Value a1; using VertexType = Vertex; static const std::size_t attributeOffsets[1]; }; template class Vertex { public: typename A1::Value a1; typename A2::Value a2; using VertexType = Vertex; static const std::size_t attributeOffsets[2]; }; template class Vertex { public: typename A1::Value a1; typename A2::Value a2; typename A3::Value a3; using VertexType = Vertex; static const std::size_t attributeOffsets[3]; }; template class Vertex { public: typename A1::Value a1; typename A2::Value a2; typename A3::Value a3; typename A4::Value a4; using VertexType = Vertex; static const std::size_t attributeOffsets[4]; }; template class Vertex { public: typename A1::Value a1; typename A2::Value a2; typename A3::Value a3; typename A4::Value a4; typename A5::Value 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); std::set getActiveAttributes(ProgramID); template class Attributes { public: using Types = TypeList; using Locations = IndexedTuple< TypeList, TypeList>; using Bindings = IndexedTuple< TypeList, TypeList>; using NamedLocations = std::vector>; using Vertex = detail::Vertex; template static constexpr std::size_t Index = TypeIndex::value; static Locations bindLocations(const ProgramID& id) { std::set activeAttributes = getActiveAttributes(id); AttributeLocation location = -1; auto bindAndIncrement = [&](const char* name) { location++; return bindAttributeLocation(id, location, name); }; return Locations{ (activeAttributes.count(As::name()) ? bindAndIncrement(As::name()) : -1)... }; } template static Locations loadNamedLocations(const Program& program) { return Locations{ program.attributeLocation(As::name())... }; } static NamedLocations getNamedLocations(const Locations& locations) { return NamedLocations{ { As::name(), locations.template get() }... }; } template static Bindings bindings(const VertexBuffer& buffer) { return Bindings { As::Type::binding(buffer, Index)... }; } static void bind(Context& context, const Locations& locations, Bindings& oldBindings, const Bindings& newBindings, std::size_t vertexOffset) { util::ignore({ (As::Type::bind(context, locations.template get(), oldBindings.template get(), newBindings.template get(), vertexOffset), 0)... }); } }; namespace detail { template struct ConcatenateAttributes; template struct ConcatenateAttributes, TypeList> { using Type = Attributes; }; } // namespace detail template using ConcatenateAttributes = typename detail::ConcatenateAttributes< typename A::Types, typename B::Types>::Type; } // namespace gl } // namespace mbgl