]> git.tdb.fi Git - libs/gl.git/commitdiff
Rework Bind and enable it to restore the old binding
authorMikko Rasa <tdb@tdb.fi>
Tue, 8 Jun 2010 17:22:30 +0000 (17:22 +0000)
committerMikko Rasa <tdb@tdb.fi>
Tue, 8 Jun 2010 17:22:30 +0000 (17:22 +0000)
Derive all simple bindable classes from Bindable
Some logic corrections in RenderPass

16 files changed:
source/bindable.h
source/framebuffer.cpp
source/framebuffer.h
source/lighting.cpp
source/lighting.h
source/material.cpp
source/material.h
source/object.cpp
source/object.h
source/program.cpp
source/program.h
source/renderbuffer.cpp
source/renderbuffer.h
source/renderpass.cpp
source/renderpass.h
source/tests.h

index e26840fa3950e977b309beeeeeca96bb3ee33e6e..d85ec78daac037710390a7949c1deb164c3dbb51 100644 (file)
@@ -29,7 +29,7 @@ protected:
        }
 
 public:
-       const T *current() const { return cur_obj; }
+       static const T *current() { return cur_obj; }
 };
 
 template<typename T>
@@ -39,7 +39,7 @@ const T *Bindable<T>::cur_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.
+does nothing upon destruction.  Optionally can restore the previous binding.
 */
 class Bind
 {
@@ -50,22 +50,58 @@ private:
        };
 
        template<typename T>
-       struct Binder: Base
+       struct Binder1: Base
        {
-               const T &obj;
+               const T *obj;
+
+               Binder1(const T *o):
+                       obj(o)
+               {
+                       if(obj)
+                               obj->bind();
+                       else
+                               T::unbind();
+               }
+
+               ~Binder1()
+               {
+                       if(obj)
+                               obj->unbind();
+               }
+       };
 
-               Binder(const T &o): obj(o) { obj.bind(); }
-               ~Binder() { obj.unbind(); }
+       template<typename T, typename U>
+       struct Binder2: Base
+       {
+               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;
 
 public:
        template<typename T>
-       Bind(const T &o): binder(new Binder<T>(o)) { }
-
-       template<typename T>
-       Bind(const T *o): binder(o ? new Binder<T>(*o) : 0) { if(!o) T::unbind(); }
+       Bind(const T *o, bool r = false):
+               binder(r ? create(o, T::current()) : create(o))
+       { }
 
 private:
        Bind(const Bind &);
@@ -73,6 +109,15 @@ private:
 
 public:
        ~Bind() { delete binder; }
+
+private:
+       template<typename T>
+       Base *create(const T *o)
+       { return new Binder1<T>(o); }
+
+       template<typename T, typename U>
+       Base *create(const T *o, const U *l)
+       { return new Binder2<T, U>(o, l); }
 };
 
 } // namespace GL
index 6941c0342d7963208324df4c39c19812442aa6b1..cf3761d0abb2d26d639ace3ac1a16c8ea9534cb9 100644 (file)
@@ -34,17 +34,20 @@ Framebuffer::~Framebuffer()
 
 void Framebuffer::bind() const
 {
-       if(!cur_fbo)
-               get(GL_VIEWPORT, sys_viewport);
-       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
-       cur_fbo = this;
-       if(width && height)
-               viewport(0, 0, width, height);
+       const Framebuffer *old = current();
+       if(set_current(this))
+       {
+               if(!old)
+                       get(GL_VIEWPORT, sys_viewport);
+               glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
+               if(width && height)
+                       viewport(0, 0, width, height);
+       }
 }
 
 void Framebuffer::attach(FramebufferAttachment attch, Renderbuffer &rbuf)
 {
-       maybe_bind();
+       bind();
        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attch, GL_RENDERBUFFER_EXT, rbuf.get_id());
        get_or_create_attachment(attch) = rbuf;
        check_size();
@@ -52,7 +55,7 @@ void Framebuffer::attach(FramebufferAttachment attch, Renderbuffer &rbuf)
 
 void Framebuffer::attach(FramebufferAttachment attch, Texture2D &tex, int level)
 {
-       maybe_bind();
+       bind();
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attch, tex.get_target(), tex.get_id(), level);
        get_or_create_attachment(attch) = tex;
        check_size();
@@ -60,7 +63,7 @@ void Framebuffer::attach(FramebufferAttachment attch, Texture2D &tex, int level)
 
 void Framebuffer::detach(FramebufferAttachment attch)
 {
-       maybe_bind();
+       bind();
        for(vector<Attachment>::iterator i=attachments.begin(); i!=attachments.end(); ++i)
                if(i->attachment==attch)
                {
@@ -76,31 +79,19 @@ void Framebuffer::detach(FramebufferAttachment attch)
 
 FramebufferStatus Framebuffer::check_status() const
 {
-       maybe_bind();
+       bind();
        return static_cast<FramebufferStatus>(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
 }
 
-const Framebuffer *Framebuffer::current()
-{
-       return cur_fbo;
-}
-
 void Framebuffer::unbind()
 {
-       if(cur_fbo)
+       if(set_current(0))
        {
                glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-               cur_fbo = 0;
                viewport(sys_viewport[0], sys_viewport[1], sys_viewport[2], sys_viewport[3]);
        }
 }
 
-void Framebuffer::maybe_bind() const
-{
-       if(cur_fbo!=this)
-               bind();
-}
-
 Framebuffer::Attachment &Framebuffer::get_or_create_attachment(FramebufferAttachment attch)
 {
        for(vector<Attachment>::iterator i=attachments.begin(); i!=attachments.end(); ++i)
@@ -126,12 +117,11 @@ void Framebuffer::check_size()
                        width = tex->get_width();
                        height = tex->get_height();
                }
-               if(cur_fbo==this)
+               if(current()==this)
                        viewport(0, 0, width, height);
        }
 }
 
-const Framebuffer *Framebuffer::cur_fbo = 0;
 int Framebuffer::sys_viewport[4] = { 0, 0, 1, 1 };
 
 
index 7c88b4cd105a7def770fc8d0b3ea404c6bac051c..b4f43f77f47473a12381eb499eb13a3c6d658c13 100644 (file)
@@ -9,6 +9,7 @@ Distributed under the LGPL
 #define MSP_GL_FRAMEBUFFER_H_
 
 #include <vector>
+#include "bindable.h"
 #include "gl.h"
 
 namespace Msp {
@@ -73,7 +74,7 @@ least one image must be attached for the framebuffer to be usable.
 
 Requires the GL_EXT_framebuffer_object extension.
 */
-class Framebuffer
+class Framebuffer: public Bindable<Framebuffer>
 {
 private:
        struct Attachment
@@ -96,7 +97,6 @@ private:
        unsigned width;
        unsigned height;
 
-       static const Framebuffer *cur_fbo;
        static int sys_viewport[4];
 
 public:
@@ -116,7 +116,6 @@ public:
        */
        FramebufferStatus check_status() const;
 
-       static const Framebuffer *current();
        static void unbind();
 private:
        void maybe_bind() const;
index 0d6e7dc4ab6e5da6a1521677a9a8689398ed6ca5..44a01a5e6ab6ade990bd324d0ea7a0f97a5c8e85 100644 (file)
@@ -39,33 +39,30 @@ void Lighting::detach(unsigned i)
 
 void Lighting::bind() const
 {
-       if(current!=this)
-       {
-               enable(LIGHTING);
-               glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &ambient.r);
-               for(unsigned i=0; i<lights.size(); ++i)
-                       if(lights[i])
-                               lights[i]->bind_to(i);
-               current = this;
-       }
+       if(!set_current(this))
+               return;
+
+       enable(LIGHTING);
+       glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &ambient.r);
+       for(unsigned i=0; i<lights.size(); ++i)
+               if(lights[i])
+                       lights[i]->bind_to(i);
 }
 
 void Lighting::unbind()
 {
-       if(current)
-       {
-               for(unsigned i=0; i<current->lights.size(); ++i)
-                       if(current->lights[i])
-                       {
-                               Light::activate(i);
-                               Light::unbind();
-                       }
-               disable(LIGHTING);
-               current = 0;
-       }
-}
+       const Lighting *old = current();
+       if(!set_current(0))
+               return;
 
-const Lighting *Lighting::current = 0;
+       for(unsigned i=0; i<old->lights.size(); ++i)
+               if(old->lights[i])
+               {
+                       Light::activate(i);
+                       Light::unbind();
+               }
+       disable(LIGHTING);
+}
 
 } // namespace GL
 } // namespace Msp
index 85d5fb0406c877cb0d89e855cc6d6cff2b90a384..31e75a44c66b36442778b7ac2d07e0add0a6f342 100644 (file)
@@ -9,6 +9,7 @@ Distributed under the LGPL
 #define MSP_GL_LIGHTING_H_
 
 #include <vector>
+#include "bindable.h"
 #include "color.h"
 #include "gl.h"
 
@@ -25,14 +26,12 @@ enum
 /**
 Encapsulates global lighting parameters and a number of individual lights.
 */
-class Lighting
+class Lighting: public Bindable<Lighting>
 {
 private:
        Color ambient;
        std::vector<const Light *> lights;
 
-       static const Lighting *current;
-
 public:
        Lighting();
 
index eee1ebc6152057d8799db1a118fa3dcda2bfcd2c..989bb12e71b7ac51e5fd2223abbc591fa9a72006 100644 (file)
@@ -46,24 +46,21 @@ void Material::set_shininess(float s)
 
 void Material::bind() const
 {
-       if(current!=this)
+       if(set_current(this))
        {
                glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r);
                glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r);
                glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r);
                glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &emission.r);
                glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
-               current = this;
        }
 }
 
 void Material::unbind()
 {
-       current = 0;
+       set_current(0);
 }
 
-const Material *Material::current = 0;
-
 
 Material::Loader::Loader(Material &m):
        DataFile::ObjectLoader<Material>(m)
index 6614aeeae12cac4c51b0e9b91c320106b256eea1..fa1612e142d1dca596fe58a59e03491d74b0fc70 100644 (file)
@@ -9,6 +9,7 @@ Distributed under the LGPL
 #define MSP_GL_MATERIAL_H_
 
 #include <msp/datafile/objectloader.h>
+#include "bindable.h"
 #include "color.h"
 
 namespace Msp {
@@ -18,7 +19,7 @@ namespace GL {
 Stores OpenGL material properties.  Since OpenGL does not support material
 objects, application of material is done with several calls to glMaterial.
 */
-class Material
+class Material: public Bindable<Material>
 {
 public:
        class Loader: public DataFile::ObjectLoader<Material>
@@ -55,8 +56,6 @@ public:
        void bind() const;
 
        static void unbind();
-private:
-       static const Material *current;
 };
 
 } // namespace GL
index 938e83f911211cd75b2e50302b6ad00d67345005..5ae04feb03027dd078a99335d651adce924bfa2c 100644 (file)
@@ -44,7 +44,7 @@ void Object::render(const Tag &tag) const
        if(!pass)
                return;
 
-       Bind bind(*pass);
+       Bind bind(pass);
        meshes[0]->draw();
 }
 
@@ -54,14 +54,14 @@ void Object::render(const ObjectInstance &inst, const Tag &tag) const
        if(!pass)
                return;
 
-       Bind bind(*pass);
+       Bind bind(pass);
        render_instance(inst, tag);
        meshes[0]->draw();
 }
 
 const RenderPass *Object::get_pass(const Tag &tag) const
 {
-       if(!technique->has_pass(tag))
+       if(!technique || !technique->has_pass(tag))
                return 0;
        return &technique->get_pass(tag);
 }
index bff41bf108e3f153fb6383f8fd09eb8dc91ec3bc..2b5f4a850d8aa7b483fde3cf1eb932d4c9efc9e2 100644 (file)
@@ -82,7 +82,7 @@ public:
                if(!pass)
                        return;
 
-               Bind bind(*pass);
+               Bind bind(pass);
                for(Iter i=begin; i!=end; ++i)
                        render_instance(**i, tag);
        }
index ef1f4c8a63fc0696f363bf21e10b60cb8fe4b80f..1f28e9565e19905e1770bce0de872621b25225f7 100644 (file)
@@ -113,8 +113,10 @@ void Program::bind() const
        if(!linked)
                throw InvalidState("Program is not linked");
 
+       if(!set_current(this))
+               return;
+
        glUseProgramObjectARB(id);
-       cur_prog = this;
 }
 
 int Program::get_uniform_location(const string &n) const
@@ -124,21 +126,12 @@ int Program::get_uniform_location(const string &n) const
 
 void Program::unbind()
 {
-       if(cur_prog)
-       {
-               glUseProgramObjectARB(0);
-               cur_prog = 0;
-       }
-}
+       if(!set_current(0))
+               return;
 
-void Program::maybe_bind()
-{
-       if(cur_prog!=this)
-               bind();
+       glUseProgramObjectARB(0);
 }
 
-const Program *Program::cur_prog = 0;
-
 
 Program::Loader::Loader(Program &p):
        DataFile::ObjectLoader<Program>(p)
index af506fe8c57b1128a5354e1515c20059bcccdb1e..63d43e0f800f65b9ac58b7df6017c6bf7b51588f 100644 (file)
@@ -11,6 +11,7 @@ Distributed under the LGPL
 #include <list>
 #include <string>
 #include <msp/datafile/objectloader.h>
+#include "bindable.h"
 #include "gl.h"
 
 namespace Msp {
@@ -18,7 +19,7 @@ namespace GL {
 
 class Shader;
 
-class Program
+class Program: public Bindable<Program>
 {
 private:
        unsigned id;
@@ -26,8 +27,6 @@ private:
        bool del_shaders;
        bool linked;
 
-       static const Program *cur_prog;
-
 public:
        class Loader: public DataFile::ObjectLoader<Program>
        {
@@ -61,9 +60,6 @@ public:
        int get_uniform_location(const std::string &) const;
 
        static void unbind();
-
-private:
-       void maybe_bind();
 };
 
 } // namespace GL
index 31a623ea617a179500c1cc821ffc232134d2ce09..0d3a76b57b125af9dd470b24d9da79431b1871b4 100644 (file)
@@ -25,11 +25,6 @@ Renderbuffer::~Renderbuffer()
        glDeleteRenderbuffersEXT(1, &id);
 }
 
-void Renderbuffer::bind() const
-{
-       glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id);
-}
-
 void Renderbuffer::storage(PixelFormat fmt, unsigned w, unsigned h)
 {
        bind();
@@ -38,5 +33,17 @@ void Renderbuffer::storage(PixelFormat fmt, unsigned w, unsigned h)
        glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, fmt, width, height);
 }
 
+void Renderbuffer::bind() const
+{
+       if(set_current(this))
+               glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id);
+}
+
+void Renderbuffer::unbind()
+{
+       if(set_current(0))
+               glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+}
+
 } // namespace GL
 } // namespace Msp
index b7320929f2f977c98fec344eee7a5ff3ded1bbc8..b88db17a8a25a6417835290c1caf8fc0273d3712 100644 (file)
@@ -8,6 +8,7 @@ Distributed under the LGPL
 #ifndef MSP_GL_RENDERBUFFER_H_
 #define MSP_GL_RENDERBUFFER_H_
 
+#include "bindable.h"
 #include "pixelformat.h"
 
 namespace Msp {
@@ -20,7 +21,7 @@ correctly but that is not needed as a texture later.
 
 Requires the GL_EXT_framebuffer_object extension.
 */
-class Renderbuffer
+class Renderbuffer: public Bindable<Renderbuffer>
 {
 private:
        unsigned id;
@@ -35,9 +36,11 @@ public:
        unsigned get_width() const { return width; }
        unsigned get_height() const { return height; }
 
+       void storage(PixelFormat fmt, unsigned width, unsigned height);
+
        void bind() const;
 
-       void storage(PixelFormat fmt, unsigned width, unsigned height);
+       static void unbind();
 };
 
 } // namespace GL
index 4aa41dba2d0136a1f164a843003fcd31f8a62463..70fa546afcddc0a0f2bcafb04da1313ddbd2b85b 100644 (file)
@@ -19,8 +19,6 @@ using namespace std;
 namespace Msp {
 namespace GL {
 
-const RenderPass *RenderPass::current = 0;
-
 RenderPass::RenderPass():
        shprog(0),
        shdata(0),
@@ -64,23 +62,21 @@ void RenderPass::set_texture(const string &slot, const Texture *tex)
 
 void RenderPass::bind() const
 {
-       if(this==current)
+       const RenderPass *old = current();
+       if(!set_current(this))
                return;
 
-       const RenderPass *old = current;
-       current = this;
-
        if(shprog)
        {
                shprog->bind();
                shdata->apply();
        }
-       else if(old && !old->shprog)
+       else if(old && old->shprog)
                GL::Program::unbind();
 
        if(material)
                material->bind();
-       else if(old && !old->material)
+       else if(old && old->material)
                GL::Material::unbind();
 
        for(unsigned i=0; i<textures.size(); ++i)
@@ -95,19 +91,18 @@ void RenderPass::bind() const
 
 void RenderPass::unbind()
 {
-       if(current)
-       {
-               if(current->shprog)
-                       GL::Program::unbind();
+       const RenderPass *old = current();
+       if(!set_current(0))
+               return;
 
-               if(current->material)
-                       GL::Material::unbind();
+       if(old->shprog)
+               GL::Program::unbind();
 
-               for(unsigned i=current->textures.size(); i--; )
-                       GL::Texture::unbind_from(i);
+       if(old->material)
+               GL::Material::unbind();
 
-               current = 0;
-       }
+       for(unsigned i=old->textures.size(); i--; )
+               GL::Texture::unbind_from(i);
 }
 
 
index 94c6bc02b085885a4e7dea3bdad21447b33922f7..e2ea4c97175eb6a62e14bfa6ec636a4c63b12b1d 100644 (file)
@@ -9,6 +9,7 @@ Distributed under the LGPL
 #define MSP_GL_RENDERPASS_H_
 
 #include <msp/datafile/objectloader.h>
+#include "bindable.h"
 
 namespace Msp {
 namespace GL {
@@ -22,7 +23,7 @@ class Texture;
 Encapsulates the data that determines the appearance of a rendered surface.
 This includes shader and data for it, material and textures.
 */
-class RenderPass
+class RenderPass: public Bindable<RenderPass>
 {
 public:
        class Loader: public DataFile::CollectionObjectLoader<RenderPass>
@@ -61,8 +62,6 @@ private:
        const Material *material;
        std::vector<TextureSlot> textures;
 
-       static const RenderPass *current;
-
        RenderPass &operator=(const RenderPass &);
 public:
        RenderPass();
index 622834dcf888db6abb982abf1721a3291d8cc439..75d15036c64a12a2148abfaa0ce6f7d88f20ca1f 100644 (file)
@@ -54,8 +54,6 @@ private:
        bool write;
        Predicate pred;
 
-       static const DepthTest *current; 
-
 public:
        DepthTest();
        DepthTest(Predicate, bool = true);