]> git.tdb.fi Git - libs/gl.git/blobdiff - source/framebuffer.cpp
Rework Bind and enable it to restore the old binding
[libs/gl.git] / source / framebuffer.cpp
index 7ae391a4a18c600dfe68c7461419dcaf3928d412..cf3761d0abb2d26d639ace3ac1a16c8ea9534cb9 100644 (file)
@@ -8,13 +8,18 @@ Distributed under the LGPL
 #include "extension.h"
 #include "ext_framebuffer_object.h"
 #include "framebuffer.h"
+#include "misc.h"
 #include "renderbuffer.h"
 #include "texture2d.h"
 
+using namespace std;
+
 namespace Msp {
 namespace GL {
 
-Framebuffer::Framebuffer()
+Framebuffer::Framebuffer():
+       width(0),
+       height(0)
 {
        static RequireExtension _ext("GL_EXT_framebuffer_object");
 
@@ -29,49 +34,136 @@ Framebuffer::~Framebuffer()
 
 void Framebuffer::bind() const
 {
-       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
-       cur_fbo=this;
+       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();
 }
 
 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();
 }
 
-FramebufferStatus Framebuffer::check_status() const
+void Framebuffer::detach(FramebufferAttachment attch)
 {
-       maybe_bind();
-       return static_cast<FramebufferStatus>(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
+       bind();
+       for(vector<Attachment>::iterator i=attachments.begin(); i!=attachments.end(); ++i)
+               if(i->attachment==attch)
+               {
+                       if(i->type==GL_RENDERBUFFER_EXT)
+                               glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attch, GL_RENDERBUFFER_EXT, 0);
+                       else if(i->type==GL_TEXTURE_2D)
+                               glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attch, GL_TEXTURE_2D, 0, 0);
+                       attachments.erase(i);
+                       check_size();
+                       return;
+               }
 }
 
-const Framebuffer *Framebuffer::current()
+FramebufferStatus Framebuffer::check_status() const
 {
-       return cur_fbo;
+       bind();
+       return static_cast<FramebufferStatus>(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
 }
 
 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
+Framebuffer::Attachment &Framebuffer::get_or_create_attachment(FramebufferAttachment attch)
 {
-       if(cur_fbo!=this)
-               bind();
+       for(vector<Attachment>::iterator i=attachments.begin(); i!=attachments.end(); ++i)
+               if(i->attachment==attch)
+                       return *i;
+       attachments.push_back(Attachment(attch));
+       return attachments.back();
 }
 
-const Framebuffer *Framebuffer::cur_fbo=0;
+void Framebuffer::check_size()
+{
+       if(!attachments.empty())
+       {
+               const Attachment &attch = attachments.front();
+               if(attch.type==GL_RENDERBUFFER_EXT)
+               {
+                       width = attch.rbuf->get_width();
+                       height = attch.rbuf->get_height();
+               }
+               else if(attch.type==GL_TEXTURE_2D)
+               {
+                       Texture2D *tex = static_cast<Texture2D *>(attch.tex);
+                       width = tex->get_width();
+                       height = tex->get_height();
+               }
+               if(current()==this)
+                       viewport(0, 0, width, height);
+       }
+}
+
+int Framebuffer::sys_viewport[4] = { 0, 0, 1, 1 };
+
+
+Framebuffer::Attachment::Attachment(FramebufferAttachment a):
+       attachment(a),
+       type(0)
+{ }
+
+Framebuffer::Attachment &Framebuffer::Attachment::operator=(Renderbuffer &r)
+{
+       type = GL_RENDERBUFFER_EXT;
+       rbuf = &r;
+       return *this;
+}
+
+Framebuffer::Attachment &Framebuffer::Attachment::operator=(Texture &t)
+{
+       type = t.get_target();
+       tex = &t;
+       return *this;
+}
+
+
+void viewport(int x, int y, unsigned w, unsigned h)
+{
+       glViewport(x, y, w, h);
+}
+
+void clear(BufferBits bits)
+{
+       glClear(bits);
+}
+
+void draw_buffer(RWBuffer buf)
+{
+       glDrawBuffer(buf);
+}
+
+void read_buffer(RWBuffer buf)
+{
+       glReadBuffer(buf);
+}
 
 } // namespace GL
 } // namespace Msp