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