#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { namespace gl { class AttributeBinding { public: gfx::AttributeDescriptor attribute; uint8_t vertexStride; BufferID vertexBuffer; uint32_t vertexOffset; friend bool operator==(const AttributeBinding& lhs, const AttributeBinding& rhs) { return std::tie(lhs.attribute, lhs.vertexStride, lhs.vertexBuffer, lhs.vertexOffset) == std::tie(rhs.attribute, rhs.vertexStride, rhs.vertexBuffer, rhs.vertexOffset); } }; using AttributeBindingArray = std::vector>; /* 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 AttributeBinding attributeBinding(const VertexBuffer& buffer) { static_assert(I < gfx::VertexDescriptorOf::data.count, "vertex attribute index out of range"); return { gfx::VertexDescriptorOf::data.attributes[I], gfx::VertexDescriptorOf::data.stride, buffer.buffer, 0, }; } optional offsetAttributeBinding(const optional& binding, std::size_t vertexOffset); class Context; void bindAttributeLocation(Context&, ProgramID, AttributeLocation, const char * name); std::set getActiveAttributes(ProgramID); template class Attributes; template class Attributes> final { public: using Types = TypeList; using Locations = IndexedTuple< TypeList, TypeList>...>>; using Bindings = IndexedTuple< TypeList, TypeList>...>>; using NamedLocations = std::vector>; static Locations bindLocations(Context& context, const ProgramID& id) { std::set activeAttributes = getActiveAttributes(id); AttributeLocation location = 0; auto maybeBindLocation = [&](const char* name) -> optional { if (activeAttributes.count(name)) { bindAttributeLocation(context, id, location, name); return location++; } else { return {}; } }; return Locations { maybeBindLocation(As::name())... }; } template 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& location) { if (location) { result.emplace_back(name, *location); } }; util::ignore({ (maybeAddLocation(As::name(), locations.template get()), 0)... }); return result; } static Bindings bindings(const VertexBuffer>& buffer) { return Bindings { attributeBinding::value>(buffer)... }; } static Bindings offsetBindings(const Bindings& bindings, std::size_t vertexOffset) { return Bindings { offsetAttributeBinding(bindings.template get(), vertexOffset)... }; } static AttributeBindingArray toBindingArray(const Locations& locations, const Bindings& bindings) { AttributeBindingArray result; result.resize(sizeof...(As)); auto maybeAddBinding = [&] (const optional& location, const optional& binding) { if (location) { result.at(*location) = binding; } }; util::ignore({ (maybeAddBinding(locations.template get(), bindings.template get()), 0)... }); return result; } static uint32_t activeBindingCount(const Bindings& bindings) { uint32_t result = 0; util::ignore({ ((result += bool(bindings.template get())), 0)... }); return result; } }; } // namespace gl } // namespace mbgl