1 #pragma once
2 
3 #include <tuple>
4 
5 namespace mbgl {
6 namespace gl {
7 
8 // Wraps a piece of OpenGL state and remember its value to avoid redundant state calls.
9 // Wrapped types need to implement to the Value class interface:
10 //
11 // class Value {
12 //     using Type = ...;
13 //     static const constexpr Type Default = ...;
14 //     static void Set(const Type& value);
15 //     static Type Get();
16 // };
17 template <typename T, typename... Args>
18 class State {
19 public:
State(Args &&...args)20     State(Args&&... args) : params(std::forward_as_tuple(::std::forward<Args>(args)...)) {
21     }
22 
operator =(const typename T::Type & value)23     void operator=(const typename T::Type& value) {
24         if (*this != value) {
25             setCurrentValue(value);
26             set(std::index_sequence_for<Args...>{});
27         }
28     }
29 
operator ==(const typename T::Type & value) const30     bool operator==(const typename T::Type& value) const {
31         return !(*this != value);
32     }
33 
operator !=(const typename T::Type & value) const34     bool operator!=(const typename T::Type& value) const {
35         return dirty || currentValue != value;
36     }
37 
setCurrentValue(const typename T::Type & value)38     void setCurrentValue(const typename T::Type& value) {
39         dirty = false;
40         currentValue = value;
41     }
42 
43     // Mark the state as dirty. This means that the next time we are assigning a value to this
44     // piece of OpenGL state will always result in an actual OpenGL call.
setDirty()45     void setDirty() {
46         dirty = true;
47     }
48 
getCurrentValue() const49     typename T::Type getCurrentValue() const {
50         return currentValue;
51     }
52 
isDirty() const53     bool isDirty() const {
54         return dirty;
55     }
56 
57 private:
58     template <std::size_t... I>
set(std::index_sequence<I...>)59     void set(std::index_sequence<I...>) {
60         T::Set(currentValue, std::get<I>(params)...);
61     }
62 
63 private:
64     typename T::Type currentValue = T::Default;
65     bool dirty = true;
66     const std::tuple<Args...> params;
67 };
68 
69 } // namespace gl
70 } // namespace mbgl
71