]> git.tdb.fi Git - libs/gl.git/blob - source/bindable.h
Add support for multiple binding points in the RAII binders
[libs/gl.git] / source / bindable.h
1 #ifndef MSP_GL_BINDABLE_H_
2 #define MSP_GL_BINDABLE_H_
3
4 namespace Msp {
5 namespace GL {
6
7 /**
8 A helper class for single-point binding.  Provides tracking of the currently
9 bound object.
10 */
11 template<typename T>
12 class Bindable
13 {
14 protected:
15         static const T *cur_obj;
16
17         Bindable() { }
18
19         static bool set_current(const T *obj)
20         {
21                 if(obj==cur_obj)
22                         return false;
23
24                 cur_obj = obj;
25                 return true;
26         }
27
28 public:
29         static const T *current() { return cur_obj; }
30 };
31
32 template<typename T>
33 const T *Bindable<T>::cur_obj;
34
35
36 /**
37 A helper class for Bindables that revert to a default object on unbind.
38 */
39 template<typename T>
40 class BindableWithDefault: protected Bindable<T>
41 {
42 protected:
43         BindableWithDefault() { }
44
45 public:
46         static const T *current()
47         {
48                 if(!Bindable<T>::cur_obj)
49                         Bindable<T>::cur_obj = &default_object();
50                 return Bindable<T>::cur_obj;
51         }
52
53         static void unbind()
54         {
55                 default_object().bind();
56         }
57
58         static const T &default_object()
59         {
60                 static T obj;
61                 return obj;
62         }
63 };
64
65
66 /**
67 RAII class for binding things.  Binds the thing upon construction and unbinds
68 it upon destruction.  If a null pointer is given, unbinds upon construction and
69 does nothing upon destruction.
70 */
71 class Bind
72 {
73 private:
74         typedef void CleanupFunc(int);
75
76         int slot;
77         CleanupFunc *cleanup;
78
79 public:
80         template<typename T>
81         Bind(T *o) { init(o); }
82
83         template<typename T>
84         Bind(const T *o) { init(o); }
85
86         template<typename T>
87         Bind(const T &o) { init(&o); }
88
89         template<typename T, typename S>
90         Bind(T *o, S s) { init(o, s); }
91
92         template<typename T, typename S>
93         Bind(const T *o, S s) { init(o, s); }
94
95         template<typename T, typename S>
96         Bind(const T &o, S s) { init(&o, s); }
97
98 private:
99         template<typename T>
100         void init(const T *o)
101         {
102                 cleanup = (o ? &unbind<T> : 0);
103                 if(o)
104                         o->bind();
105                 else
106                         T::unbind();
107         }
108
109         template<typename T, typename S>
110         void init(const T *o, S s)
111         {
112                 cleanup = (o ? &unbind_from<T, S> : 0);
113                 slot = s;
114                 if(o)
115                         o->bind_to(s);
116                 else
117                         T::unbind_from(s);
118         }
119
120 public:
121         ~Bind()
122         { if(cleanup) cleanup(slot); }
123
124 private:
125         template<typename T>
126         static void unbind(int)
127         { T::unbind(); }
128
129         template<typename T, typename S>
130         static void unbind_from(int s)
131         { T::unbind_from(static_cast<S>(s)); }
132 };
133
134
135 /**
136 Similar to Bind, but restores previous binding upon destruction.
137 */
138 class BindRestore
139 {
140 private:
141         typedef void CleanupFunc(const void *, int);
142
143         const void *old;
144         int slot;
145         CleanupFunc *cleanup;
146
147 public:
148         template<typename T>
149         BindRestore(T *o) { init(o); }
150
151         template<typename T>
152         BindRestore(const T *o) { init(o); }
153
154         template<typename T>
155         BindRestore(const T &o) { init(&o); }
156
157         template<typename T, typename S>
158         BindRestore(T *o, S s) { init(o, s); }
159
160         template<typename T, typename S>
161         BindRestore(const T *o, S s) { init(o, s); }
162
163         template<typename T, typename S>
164         BindRestore(const T &o, S s) { init(&o, s); }
165
166 private:
167         template<typename T>
168         void init(T *o)
169         {
170                 old = T::current();
171                 cleanup = (o!=old ? &restore<T> : 0);
172                 if(o)
173                         o->bind();
174                 else if(old)
175                         T::unbind();
176         }
177
178         template<typename T, typename S>
179         void init(T *o, S s)
180         {
181                 old = T::current(s);
182                 slot = s;
183                 cleanup = (o!=old ? &restore_to<T, S> : 0);
184                 if(o)
185                         o->bind_to(s);
186                 else if(old)
187                         T::unbind_from(s);
188         }
189
190 public:
191         ~BindRestore()
192         { if(cleanup) cleanup(old, slot); }
193
194 private:
195         template<typename T>
196         static void restore(const void *o, int)
197         {
198                 if(o)
199                         reinterpret_cast<const T *>(o)->bind();
200                 else
201                         T::unbind();
202         }
203
204         template<typename T, typename S>
205         static void restore_to(const void *o, int si)
206         {
207                 S s = static_cast<S>(si);
208                 if(o)
209                         reinterpret_cast<const T *>(o)->bind_to(s);
210                 else
211                         T::unbind_from(s);
212         }
213 };
214
215 } // namespace GL
216 } // namespace Msp
217
218 #endif