#pragma once #include #include #include #include #include #include #include #include namespace mbgl { namespace gl { template void bindUniform(UniformLocation, const T&); template class UniformValue { public: explicit UniformValue(T t_) : t(std::move(t_)) {} T t; }; class ActiveUniform { public: std::size_t size; UniformDataType type; }; #ifndef NDEBUG template bool verifyUniform(const ActiveUniform&); using ActiveUniforms = std::map; ActiveUniforms activeUniforms(ProgramID); #endif template class Uniform { public: using Value = UniformValue; using Type = T; class State { public: void operator=(const Value& value) { if (location >= 0 && (!current || *current != value.t)) { current = value.t; bindUniform(location, value.t); } } UniformLocation location; optional current = {}; }; }; template using UniformScalar = Uniform; template using UniformVector = Uniform>; template using UniformMatrix = Uniform>; #define MBGL_DEFINE_UNIFORM_SCALAR(type_, name_) \ struct name_ : ::mbgl::gl::UniformScalar { static auto name() { return #name_; } } #define MBGL_DEFINE_UNIFORM_VECTOR(type_, n_, name_) \ struct name_ : ::mbgl::gl::UniformVector { static auto name() { return #name_; } } #define MBGL_DEFINE_UNIFORM_MATRIX(type_, n_, name_) \ struct name_ : ::mbgl::gl::UniformMatrix { static auto name() { return #name_; } } UniformLocation uniformLocation(ProgramID, const char * name); template class Uniforms { public: using Types = TypeList; using State = IndexedTuple, TypeList>; using Values = IndexedTuple, TypeList>; using NamedLocations = std::vector>; static State bindLocations(const ProgramID& id) { #ifndef NDEBUG // Verify active uniform types match the enum const auto active = activeUniforms(id); util::ignore( { // Some shader programs have uniforms declared, but not used, so they're not active. // Therefore, we'll only verify them when they are indeed active. (active.find(Us::name()) != active.end() ? verifyUniform(active.at(Us::name())) : false)... }); #endif return State { { uniformLocation(id, Us::name()) }... }; } template static State loadNamedLocations(const Program& program) { return State{ { program.uniformLocation(Us::name()) }... }; } static NamedLocations getNamedLocations(const State& state) { return NamedLocations{ { Us::name(), state.template get().location }... }; } static void bind(State& state, Values&& values) { util::ignore({ (state.template get() = values.template get(), 0)... }); } }; namespace detail { template struct ConcatenateUniforms; template struct ConcatenateUniforms, TypeList> { using Type = Uniforms; }; } // namespace detail template using ConcatenateUniforms = typename detail::ConcatenateUniforms< typename A::Types, typename B::Types>::Type; } // namespace gl } // namespace mbgl