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