X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fbindable.h;h=b2634ea92bd4b1b43bb1f88b502af230f1e3c4bd;hp=e26840fa3950e977b309beeeeeca96bb3ee33e6e;hb=4b4d2a48048268d2ad48bafbce8647af8088573f;hpb=b617c5d7b5283ad260a77f01e42e6170cabbc03d diff --git a/source/bindable.h b/source/bindable.h index e26840fa..b2634ea9 100644 --- a/source/bindable.h +++ b/source/bindable.h @@ -1,16 +1,13 @@ -/* $Id$ - -This file is part of libmspgl -Copyright © 2010 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - #ifndef MSP_GL_BINDABLE_H_ #define MSP_GL_BINDABLE_H_ namespace Msp { namespace GL { +/** +A helper class for single-point binding. Provides tracking of the currently +bound object. +*/ template class Bindable { @@ -18,6 +15,7 @@ protected: static const T *cur_obj; Bindable() { } + ~Bindable() { if(cur_obj==this) T::unbind(); } static bool set_current(const T *obj) { @@ -29,13 +27,47 @@ protected: } public: - const T *current() const { return cur_obj; } + static const T *current() { return cur_obj; } }; template const T *Bindable::cur_obj; +/** +A helper class for Bindables that revert to a default object on unbind. +*/ +template +class BindableWithDefault: protected Bindable +{ + friend class Bindable; + +protected: + BindableWithDefault() { } + ~BindableWithDefault() { if(this==&default_object()) Bindable::set_current(0); } + +public: + static const T *current() + { + if(!Bindable::cur_obj) + Bindable::cur_obj = &default_object(); + return Bindable::cur_obj; + } + + static void unbind() + { + if(Bindable::cur_obj) + 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 @@ -44,35 +76,147 @@ 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 + 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 - struct Binder: Base + void init(const T *o) { - const T &obj; + cleanup = (o ? static_cast(&unbind) : 0); + slot = 0; + if(o) + o->bind(); + else + T::unbind(); + } + + template + void init(const T *o, S s) + { + cleanup = (o ? static_cast(&unbind_from) : 0); + slot = s; + if(o) + o->bind_to(s); + else + T::unbind_from(s); + } + +public: + ~Bind() + { if(cleanup) cleanup(slot); } + +private: + template + static void unbind(int) + { T::unbind(); } - Binder(const T &o): obj(o) { obj.bind(); } - ~Binder() { obj.unbind(); } - }; + template + static void unbind_from(int s) + { T::unbind_from(static_cast(s)); } +}; - Base *binder; + +/** +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): binder(new Binder(o)) { } + BindRestore(T *o) { init(o); } + + template + BindRestore(const T *o) { init(o); } template - Bind(const T *o): binder(o ? new Binder(*o) : 0) { if(!o) T::unbind(); } + 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(); + slot = 0; + cleanup = (o!=old ? static_cast(&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 ? static_cast(&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 + static void restore(const void *o, int) + { + if(o) + reinterpret_cast(o)->bind(); + else + T::unbind(); + } + + 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