]> git.tdb.fi Git - libs/gl.git/blob - source/bindable.h
Make older gcc versions happy
[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 ? static_cast<CleanupFunc *>(&unbind<T>) : 0);
103                 slot = 0;
104                 if(o)
105                         o->bind();
106                 else
107                         T::unbind();
108         }
109
110         template<typename T, typename S>
111         void init(const T *o, S s)
112         {
113                 cleanup = (o ? static_cast<CleanupFunc *>(&unbind_from<T, S>) : 0);
114                 slot = s;
115                 if(o)
116                         o->bind_to(s);
117                 else
118                         T::unbind_from(s);
119         }
120
121 public:
122         ~Bind()
123         { if(cleanup) cleanup(slot); }
124
125 private:
126         template<typename T>
127         static void unbind(int)
128         { T::unbind(); }
129
130         template<typename T, typename S>
131         static void unbind_from(int s)
132         { T::unbind_from(static_cast<S>(s)); }
133 };
134
135
136 /**
137 Similar to Bind, but restores previous binding upon destruction.
138 */
139 class BindRestore
140 {
141 private:
142         typedef void CleanupFunc(const void *, int);
143
144         const void *old;
145         int slot;
146         CleanupFunc *cleanup;
147
148 public:
149         template<typename T>
150         BindRestore(T *o) { init(o); }
151
152         template<typename T>
153         BindRestore(const T *o) { init(o); }
154
155         template<typename T>
156         BindRestore(const T &o) { init(&o); }
157
158         template<typename T, typename S>
159         BindRestore(T *o, S s) { init(o, s); }
160
161         template<typename T, typename S>
162         BindRestore(const T *o, S s) { init(o, s); }
163
164         template<typename T, typename S>
165         BindRestore(const T &o, S s) { init(&o, s); }
166
167 private:
168         template<typename T>
169         void init(T *o)
170         {
171                 old = T::current();
172                 slot = 0;
173                 cleanup = (o!=old ? static_cast<CleanupFunc *>(&restore<T>) : 0);
174                 if(o)
175                         o->bind();
176                 else if(old)
177                         T::unbind();
178         }
179
180         template<typename T, typename S>
181         void init(T *o, S s)
182         {
183                 old = T::current(s);
184                 slot = s;
185                 cleanup = (o!=old ? static_cast<CleanupFunc *>(&restore_to<T, S>) : 0);
186                 if(o)
187                         o->bind_to(s);
188                 else if(old)
189                         T::unbind_from(s);
190         }
191
192 public:
193         ~BindRestore()
194         { if(cleanup) cleanup(old, slot); }
195
196 private:
197         template<typename T>
198         static void restore(const void *o, int)
199         {
200                 if(o)
201                         reinterpret_cast<const T *>(o)->bind();
202                 else
203                         T::unbind();
204         }
205
206         template<typename T, typename S>
207         static void restore_to(const void *o, int si)
208         {
209                 S s = static_cast<S>(si);
210                 if(o)
211                         reinterpret_cast<const T *>(o)->bind_to(s);
212                 else
213                         T::unbind_from(s);
214         }
215 };
216
217 } // namespace GL
218 } // namespace Msp
219
220 #endif