diff options
Diffstat (limited to 'src/mbgl/gl/uniform.hpp')
-rw-r--r-- | src/mbgl/gl/uniform.hpp | 95 |
1 files changed, 61 insertions, 34 deletions
diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp index 5af781043d..d233614aa6 100644 --- a/src/mbgl/gl/uniform.hpp +++ b/src/mbgl/gl/uniform.hpp @@ -1,60 +1,87 @@ #pragma once #include <mbgl/gl/shader.hpp> +#include <mbgl/util/optional.hpp> #include <array> +#include <functional> +#include <tuple> namespace mbgl { namespace gl { -template <typename T> +template <class T> +void bindUniform(UniformLocation, const T&); + +template <class Tag, class T> class Uniform { public: - Uniform(const char* name, const Shader& shader) - : current(), location(shader.getUniformLocation(name)) { - } + class Value { + public: + Value(T t_) : t(std::move(t_)) {} + T t; + }; - void operator=(const T& t) { - if (current != t) { - current = t; - bind(t); - } - } + class State { + public: + State(const char* name, const Shader& shader) + : location(shader.getUniformLocation(name)) {} -private: - void bind(const T&); + void operator=(const Value& value) { + if (!current || *current != value.t) { + current = value.t; + bindUniform(location, value.t); + } + } - T current; - UniformLocation location; + private: + optional<T> current; + UniformLocation location; + }; }; -template <size_t C, size_t R = C> -class UniformMatrix { +template <class Tag, class T> +using UniformScalar = Uniform<Tag, T>; + +template <class Tag, class T, size_t N> +using UniformVector = Uniform<Tag, std::array<T, N>>; + +template <class Tag, class T, size_t N> +using UniformMatrix = Uniform<Tag, std::array<T, N*N>>; + +#define MBGL_DEFINE_UNIFORM_SCALAR(type_, name_) \ + struct name_ : ::mbgl::gl::UniformScalar<name_, type_> { static constexpr auto name = #name_; } + +#define MBGL_DEFINE_UNIFORM_VECTOR(type_, n_, name_) \ + struct name_ : ::mbgl::gl::UniformVector<name_, type_, n_> { static constexpr auto name = #name_; } + +#define MBGL_DEFINE_UNIFORM_MATRIX(type_, n_, name_) \ + struct name_ : ::mbgl::gl::UniformMatrix<name_, type_, n_> { static constexpr auto name = #name_; } + +template <class... Us> +class Uniforms { public: - typedef std::array<float, C*R> T; + using State = std::tuple<typename Us::State...>; + using Values = std::tuple<typename Us::Value...>; - UniformMatrix(const char* name, const Shader& shader) - : current(), location(shader.getUniformLocation(name)) { + static State state(const Shader& shader) { + return State { { Us::name, shader }... }; } - void operator=(const std::array<double, C*R>& t) { - bool dirty = false; - for (unsigned int i = 0; i < C*R; i++) { - if (current[i] != t[i]) { - current[i] = t[i]; - dirty = true; - } - } - if (dirty) { - bind(current); - } + template <class... Args> + static Values values(Args&&... args) { + return Values { std::forward<Args>(args)... }; } -private: - void bind(const T&); + static std::function<void ()> binder(State& state, Values&& values_) { + return [&state, values = std::move(values_)] () mutable { + noop((std::get<typename Us::State>(state) = std::get<typename Us::Value>(values), 0)...); + }; + } - T current; - UniformLocation location; +private: + // This exists only to provide a varags context for unpacking the assignments in `binder`. + template <int...> static void noop(int...) {} }; } // namespace gl |