]> git.tdb.fi Git - libs/gl.git/blobdiff - source/bindable.h
Use RED format for ambient occlusion render target
[libs/gl.git] / source / bindable.h
index 000234515aeeea4a5b38effe0bf27173251b8896..b2634ea92bd4b1b43bb1f88b502af230f1e3c4bd 100644 (file)
@@ -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<typename T>
 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)
        {
@@ -36,98 +34,189 @@ template<typename T>
 const T *Bindable<T>::cur_obj;
 
 
+/**
+A helper class for Bindables that revert to a default object on unbind.
+*/
+template<typename T>
+class BindableWithDefault: protected Bindable<T>
+{
+       friend class Bindable<T>;
+
+protected:
+       BindableWithDefault() { }
+       ~BindableWithDefault() { if(this==&default_object()) Bindable<T>::set_current(0); }
+
+public:
+       static const T *current()
+       {
+               if(!Bindable<T>::cur_obj)
+                       Bindable<T>::cur_obj = &default_object();
+               return Bindable<T>::cur_obj;
+       }
+
+       static void unbind()
+       {
+               if(Bindable<T>::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
-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<typename T>
+       Bind(T *o) { init(o); }
+
+       template<typename T>
+       Bind(const T *o) { init(o); }
 
        template<typename T>
-       struct Binder1: Base
+       Bind(const T &o) { init(&o); }
+
+       template<typename T, typename S>
+       Bind(T *o, S s) { init(o, s); }
+
+       template<typename T, typename S>
+       Bind(const T *o, S s) { init(o, s); }
+
+       template<typename T, typename S>
+       Bind(const T &o, S s) { init(&o, s); }
+
+private:
+       template<typename T>
+       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<typename T, typename U>
-       struct Binder2: Base
+               cleanup = (o ? static_cast<CleanupFunc *>(&unbind<T>) : 0);
+               slot = 0;
+               if(o)
+                       o->bind();
+               else
+                       T::unbind();
+       }
+
+       template<typename T, typename S>
+       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 ? static_cast<CleanupFunc *>(&unbind_from<T, S>) : 0);
+               slot = s;
+               if(o)
+                       o->bind_to(s);
+               else
+                       T::unbind_from(s);
+       }
 
 public:
+       ~Bind()
+       { if(cleanup) cleanup(slot); }
+
+private:
        template<typename T>
-       Bind(const T &o, bool r = false):
-               binder(r ? create(&o, T::current()) : create(&o))
-       { }
+       static void unbind(int)
+       { T::unbind(); }
+
+       template<typename T, typename S>
+       static void unbind_from(int s)
+       { T::unbind_from(static_cast<S>(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<typename T>
+       BindRestore(T *o) { init(o); }
 
        template<typename T>
-       Bind(const T *o, bool r = false):
-               binder(r ? create(o, T::current()) : create(o))
-       { }
+       BindRestore(const T *o) { init(o); }
 
        template<typename T>
-       Bind(T *o, bool r = false):
-               binder(r ? create(o, T::current()) : create(o))
-       { }
+       BindRestore(const T &o) { init(&o); }
+
+       template<typename T, typename S>
+       BindRestore(T *o, S s) { init(o, s); }
+
+       template<typename T, typename S>
+       BindRestore(const T *o, S s) { init(o, s); }
+
+       template<typename T, typename S>
+       BindRestore(const T &o, S s) { init(&o, s); }
 
 private:
-       Bind(const Bind &);
-       Bind &operator=(const Bind &);
+       template<typename T>
+       void init(T *o)
+       {
+               old = T::current();
+               slot = 0;
+               cleanup = (o!=old ? static_cast<CleanupFunc *>(&restore<T>) : 0);
+               if(o)
+                       o->bind();
+               else if(old)
+                       T::unbind();
+       }
+
+       template<typename T, typename S>
+       void init(T *o, S s)
+       {
+               old = T::current(s);
+               slot = s;
+               cleanup = (o!=old ? static_cast<CleanupFunc *>(&restore_to<T, S>) : 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<typename T>
-       Base *create(const T *o)
-       { return new Binder1<T>(o); }
+       static void restore(const void *o, int)
+       {
+               if(o)
+                       reinterpret_cast<const T *>(o)->bind();
+               else
+                       T::unbind();
+       }
 
-       template<typename T, typename U>
-       Base *create(const T *o, const U *l)
-       { return new Binder2<T, U>(o, l); }
+       template<typename T, typename S>
+       static void restore_to(const void *o, int si)
+       {
+               S s = static_cast<S>(si);
+               if(o)
+                       reinterpret_cast<const T *>(o)->bind_to(s);
+               else
+                       T::unbind_from(s);
+       }
 };
 
 } // namespace GL