X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fbindable.h;h=8651c70ee066b6cbfa2e8f40cd967b0a92f148cd;hb=02feac06937ec4e8e122a833b4903ccf0bd6d030;hp=8823de5c9773209a1642f5b763887e65ca7ea5d6;hpb=f14435e58bfa0fa697a06ba9a454bb30cd37d9d8;p=libs%2Fgl.git diff --git a/source/bindable.h b/source/bindable.h index 8823de5c..8651c70e 100644 --- a/source/bindable.h +++ b/source/bindable.h @@ -4,6 +4,10 @@ namespace Msp { namespace GL { +/** +A helper class for single-point binding. Provides tracking of the currently +bound object. +*/ template class Bindable { @@ -29,98 +33,183 @@ template const T *Bindable::cur_obj; +/** +A helper class for Bindables that revert to a default object on unbind. +*/ +template +class BindableWithDefault: protected Bindable +{ +protected: + BindableWithDefault() { } + +public: + static const T *current() + { + if(!Bindable::cur_obj) + Bindable::cur_obj = &default_object(); + return Bindable::cur_obj; + } + + static void unbind() + { + default_object().bind(); + } + + static const T &default_object() + { + static T obj; + return obj; + } +}; + + /** RAII class for binding things. Binds the thing upon construction and unbinds it upon destruction. If a null pointer is given, unbinds upon construction and -does nothing upon destruction. Optionally can restore the previous binding. +does nothing upon destruction. */ class Bind { private: - struct Base - { - virtual ~Base() { } - }; + typedef void CleanupFunc(int); + + int slot; + CleanupFunc *cleanup; + +public: + template + Bind(T *o) { init(o); } + + template + Bind(const T *o) { init(o); } template - struct Binder1: Base + Bind(const T &o) { init(&o); } + + template + Bind(T *o, S s) { init(o, s); } + + template + Bind(const T *o, S s) { init(o, s); } + + template + Bind(const T &o, S s) { init(&o, s); } + +private: + template + void init(const T *o) { - const T *obj; - - Binder1(const T *o): - obj(o) - { - if(obj) - obj->bind(); - else - T::unbind(); - } - - ~Binder1() - { - if(obj) - obj->unbind(); - } - }; - - template - struct Binder2: Base + cleanup = (o ? &unbind : 0); + if(o) + o->bind(); + else + T::unbind(); + } + + template + void init(const T *o, S s) { - const T *obj; - const U *old; - - Binder2(const T *o, const U *l): - obj(o), - old(l) - { - if(obj) - obj->bind(); - else - T::unbind(); - } - - ~Binder2() - { - if(old) - old->bind(); - else if(obj) - obj->unbind(); - } - }; - - Base *binder; + cleanup = (o ? &unbind_from : 0); + slot = s; + if(o) + o->bind_to(s); + else + T::unbind_from(s); + } public: + ~Bind() + { if(cleanup) cleanup(slot); } + +private: template - Bind(const T &o, bool r = false): - binder(r ? create(&o, T::current()) : create(&o)) - { } + static void unbind(int) + { T::unbind(); } + + template + static void unbind_from(int s) + { T::unbind_from(static_cast(s)); } +}; + +/** +Similar to Bind, but restores previous binding upon destruction. +*/ +class BindRestore +{ +private: + typedef void CleanupFunc(const void *, int); + + const void *old; + int slot; + CleanupFunc *cleanup; + +public: template - Bind(const T *o, bool r = false): - binder(r ? create(o, T::current()) : create(o)) - { } + BindRestore(T *o) { init(o); } template - Bind(T *o, bool r = false): - binder(r ? create(o, T::current()) : create(o)) - { } + BindRestore(const T *o) { init(o); } + + template + BindRestore(const T &o) { init(&o); } + + template + BindRestore(T *o, S s) { init(o, s); } + + template + BindRestore(const T *o, S s) { init(o, s); } + + template + BindRestore(const T &o, S s) { init(&o, s); } private: - Bind(const Bind &); - Bind &operator=(const Bind &); + template + void init(T *o) + { + old = T::current(); + cleanup = (o!=old ? &restore : 0); + if(o) + o->bind(); + else if(old) + T::unbind(); + } + + template + void init(T *o, S s) + { + old = T::current(s); + slot = s; + cleanup = (o!=old ? &restore_to : 0); + if(o) + o->bind_to(s); + else if(old) + T::unbind_from(s); + } public: - ~Bind() { delete binder; } + ~BindRestore() + { if(cleanup) cleanup(old, slot); } private: template - Base *create(const T *o) - { return new Binder1(o); } + static void restore(const void *o, int) + { + if(o) + reinterpret_cast(o)->bind(); + else + T::unbind(); + } - template - Base *create(const T *o, const U *l) - { return new Binder2(o, l); } + template + static void restore_to(const void *o, int si) + { + S s = static_cast(si); + if(o) + reinterpret_cast(o)->bind_to(s); + else + T::unbind_from(s); + } }; } // namespace GL