]> git.tdb.fi Git - libs/gl.git/commitdiff
Add get_width() / get_height() methods to Renderbuffer and Framebuffer
authorMikko Rasa <tdb@tdb.fi>
Mon, 21 Sep 2009 13:50:58 +0000 (13:50 +0000)
committerMikko Rasa <tdb@tdb.fi>
Mon, 21 Sep 2009 13:50:58 +0000 (13:50 +0000)
Add some framebuffer-related global functions
Set viewport size when binding a framebuffer and restore it when unbinding
Allow detaching attachments from a Framebuffer
Configurable texture unit number in ShadowMap

source/framebuffer.cpp
source/framebuffer.h
source/misc.cpp
source/misc.h
source/pipeline.cpp
source/renderbuffer.cpp
source/renderbuffer.h
source/shadowmap.cpp
source/shadowmap.h

index 7ae391a4a18c600dfe68c7461419dcaf3928d412..229c7f0a094c01ce64bfc43563a62882b6606164 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,20 +34,44 @@ 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);
 }
 
 void Framebuffer::attach(FramebufferAttachment attch, Renderbuffer &rbuf)
 {
        maybe_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();
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attch, tex.get_target(), tex.get_id(), level);
+       get_or_create_attachment(attch)=tex;
+       check_size();
+}
+
+void Framebuffer::detach(FramebufferAttachment attch)
+{
+       maybe_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;
+               }
 }
 
 FramebufferStatus Framebuffer::check_status() const
@@ -62,6 +91,7 @@ void Framebuffer::unbind()
        {
                glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
                cur_fbo=0;
+               viewport(sys_viewport[0], sys_viewport[1], sys_viewport[2], sys_viewport[3]);
        }
 }
 
@@ -71,7 +101,79 @@ void Framebuffer::maybe_bind() const
                bind();
 }
 
+Framebuffer::Attachment &Framebuffer::get_or_create_attachment(FramebufferAttachment attch)
+{
+       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();
+}
+
+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(cur_fbo==this)
+                       viewport(0, 0, width, height);
+       }
+}
+
 const Framebuffer *Framebuffer::cur_fbo=0;
+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
index ce36212528bb8ea5f2c5d9863fc61cb3ec810f73..9fe4cd8bd028f1d929ead4111ddcd8f11126d619 100644 (file)
@@ -8,6 +8,7 @@ Distributed under the LGPL
 #ifndef MSP_GL_FRAMEBUFFER_H_
 #define MSP_GL_FRAMEBUFFER_H_
 
+#include <vector>
 #include "gl.h"
 #include "types.h"
 
@@ -15,6 +16,7 @@ namespace Msp {
 namespace GL {
 
 class Renderbuffer;
+class Texture;
 class Texture2D;
 
 enum FramebufferAttachment
@@ -39,6 +41,28 @@ enum FramebufferStatus
        FRAMEBUFFER_COMPLETE                      = GL_FRAMEBUFFER_COMPLETE_EXT
 };
 
+enum BufferBits
+{
+       COLOR_BUFFER_BIT   = GL_COLOR_BUFFER_BIT,
+       DEPTH_BUFFER_BIT   = GL_DEPTH_BUFFER_BIT,
+       STENCIL_BUFFER_BIT = GL_STENCIL_BUFFER_BIT,
+       ACCUM_BUFFER_BIT   = GL_ACCUM_BUFFER_BIT
+};
+
+enum RWBuffer
+{
+       NO_BUFFER      = GL_NONE,
+       FRONT_LEFT     = GL_FRONT_LEFT,
+       FRONT_RIGHT    = GL_FRONT_RIGHT,
+       BACK_LEFT      = GL_BACK_LEFT,
+       BACK_RIGHT     = GL_BACK_RIGHT,
+       FRONT          = GL_FRONT,
+       BACK           = GL_BACK,
+       LEFT           = GL_LEFT,
+       RIGHT          = GL_RIGHT,
+       FRONT_AND_BACK = GL_FRONT_AND_BACK
+};
+
 /**
 Framebuffer objects can be used to perform offscreen rendering.  The most
 common application is rendering to a texture, which can then be used for
@@ -53,9 +77,28 @@ Requires the GL_EXT_framebuffer_object extension.
 class Framebuffer
 {
 private:
+       struct Attachment
+       {
+               FramebufferAttachment attachment;
+               GLenum type;
+               union
+               {
+                       Renderbuffer *rbuf;
+                       Texture *tex;
+               };
+
+               Attachment(FramebufferAttachment);
+               Attachment &operator=(Renderbuffer &);
+               Attachment &operator=(Texture &);
+       };
+
        uint id;
+       std::vector<Attachment> attachments;
+       unsigned width;
+       unsigned height;
 
        static const Framebuffer *cur_fbo;
+       static int sys_viewport[4];
 
 public:
        Framebuffer();
@@ -65,6 +108,7 @@ public:
 
        void attach(FramebufferAttachment attch, Renderbuffer &rbuf);
        void attach(FramebufferAttachment attch, Texture2D &tex, int level);
+       void detach(FramebufferAttachment attch);
 
        /**
        Checks the completeness status of the framebuffer.  Returns
@@ -77,8 +121,18 @@ public:
        static void unbind();
 private:
        void maybe_bind() const;
+       Attachment &get_or_create_attachment(FramebufferAttachment);
+       void check_size();
 };
 
+inline BufferBits operator|(BufferBits a, BufferBits b)
+{ return static_cast<BufferBits>(static_cast<int>(a)|static_cast<int>(b)); }
+
+void viewport(int, int, unsigned, unsigned);
+void clear(BufferBits);
+void draw_buffer(RWBuffer);
+void read_buffer(RWBuffer);
+
 } // namespace GL
 } // namespace Msp
 
index 70b300a661783e5398b3ca891a6b646b3ceeae87..c09d17f550aeeaa2807818fd443340b94c7e3595 100644 (file)
@@ -33,10 +33,15 @@ void get(GLenum state, int &data)
        glGetIntegerv(state, &data);
 }
 
+void get(GLenum state, int *data)
+{
+       glGetIntegerv(state, data);
+}
+
 int get_i(GLenum state)
 {
        int data;
-       get(state, data);
+       get(state, &data);
        return data;
 }
 
index 7aa8aaf9e7fb6d41c3d4acc893b464d581675b51..11cb3a60fdc24f9d94e713f89f17cdd9bd351ca6 100644 (file)
@@ -17,7 +17,10 @@ void enable(GLenum);
 void disable(GLenum);
 void set(GLenum, bool);
 
+///Deprecated (can't properly pass an array through a reference)
 void get(GLenum, int &);
+
+void get(GLenum, int *);
 int get_i(GLenum);
 
 class Bind
index b0a38a2d3240a11cc63dd8ee9c801e22a534514e..ea8b56a30763d74b2f98c93aec18e8a4f8173b5f 100644 (file)
@@ -101,10 +101,7 @@ void Pipeline::render(const Tag &tag) const
        if(pass.lighting)
                pass.lighting->bind();
        for(vector<Effect *>::const_iterator i=pass.effects.begin(); i!=pass.effects.end(); ++i)
-       {
                (*i)->prepare();
-               glViewport(0, 0, width, height);
-       }
        for(vector<const Renderable *>::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
                (*i)->render(tag);
        for(vector<Effect *>::const_iterator i=pass.effects.end(); i--!=pass.effects.begin();)
@@ -118,13 +115,10 @@ void Pipeline::render_all() const
        if(fbo)
        {
                fbo->bind();
-               glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+               clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT);
        }
        for(vector<Effect *>::const_iterator i=effects.begin(); i!=effects.end(); ++i)
-       {
                (*i)->prepare();
-               glViewport(0, 0, width, height);
-       }
        for(vector<Tag>::const_iterator i=pass_order.begin(); i!=pass_order.end(); ++i)
                render(*i);
        for(vector<Effect *>::const_iterator i=effects.end(); i--!=effects.begin();)
index 0f52ff595ec76bccee19f30c26e3f0e5f60ae7bb..ac0a34cd92d9874484fcbaab19b0bac4f1911053 100644 (file)
@@ -30,9 +30,11 @@ void Renderbuffer::bind() const
        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id);
 }
 
-void Renderbuffer::storage(PixelFormat fmt, sizei width, sizei height)
+void Renderbuffer::storage(PixelFormat fmt, sizei w, sizei h)
 {
        bind();
+       width=w;
+       height=h;
        glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, fmt, width, height);
 }
 
index a9c25ad75b0596a148b73a4420a565128880c918..040dad44bfdbaf896194d1c9bdf9adf579d0b768 100644 (file)
@@ -25,12 +25,16 @@ class Renderbuffer
 {
 private:
        uint id;
+       sizei width;
+       sizei height;
 
 public:
        Renderbuffer();
        ~Renderbuffer();
 
        uint get_id() const { return id; }
+       sizei get_width() const { return width; }
+       sizei get_height() const { return height; }
 
        void bind() const;
 
index 3691773ad3f58d9ae41ffb1148291b10acd08d32..5f66d8984279ce55f9cfc98fcf2298d34fa31337 100644 (file)
@@ -24,6 +24,7 @@ ShadowMap::ShadowMap(unsigned s, const Scene &c, const Light &l):
        size(s),
        scene(c),
        light(l),
+       unit(3),
        radius(1)
 {
        depth_buf.set_min_filter(LINEAR);
@@ -35,7 +36,7 @@ ShadowMap::ShadowMap(unsigned s, const Scene &c, const Light &l):
        depth_buf.parameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        depth_buf.parameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        fbo.attach(DEPTH_ATTACHMENT, depth_buf, 0);
-       glDrawBuffer(GL_NONE);
+       draw_buffer(NO_BUFFER);
        Framebuffer::unbind();
        Texture::unbind();
 }
@@ -46,6 +47,11 @@ void ShadowMap::set_target(const Vector3 &t, float r)
        radius=r;
 }
 
+void ShadowMap::set_texture_unit(unsigned u)
+{
+       unit=u;
+}
+
 void ShadowMap::prepare()
 {
        const Vector4 &lpos=light.get_position();
@@ -97,8 +103,7 @@ void ShadowMap::prepare()
 
                const Framebuffer *old_fbo=Framebuffer::current();
                fbo.bind();
-               glViewport(0, 0, size, size);
-               glClear(GL_DEPTH_BUFFER_BIT);
+               clear(DEPTH_BUFFER_BIT);
                scene.render("shadow");
 
                matrix_mode(PROJECTION);
@@ -111,7 +116,7 @@ void ShadowMap::prepare()
                        Framebuffer::unbind();
        }
 
-       depth_buf.bind_to(3);
+       depth_buf.bind_to(unit);
        float diam=radius*2;
        float s_eq[4]={ matrix[0]/diam, matrix[4]/diam, matrix[8]/diam, matrix[12]/diam+0.5 };
        float t_eq[4]={ matrix[1]/diam, matrix[5]/diam, matrix[9]/diam, matrix[13]/diam+0.5 };
@@ -131,7 +136,7 @@ void ShadowMap::prepare()
 
 void ShadowMap::cleanup()
 {
-       TexUnit::activate(3);
+       TexUnit::activate(unit);
        Texture::unbind();
        disable(GL_TEXTURE_GEN_S);
        disable(GL_TEXTURE_GEN_T);
index 17e17ca9ce940344713c558f8339d9c809fdef92..29bede317d1c120ab3e9ae961aee9173a01a4672 100644 (file)
@@ -19,6 +19,12 @@ namespace GL {
 class Light;
 class Scene;
 
+/**
+Creates shadows on a Scene through a shadow map texture.  In the preparation
+phase, the scene is rendered to a depth texture from the point of view of the
+lightsource.  This texture is then used in the rendering phase together with
+texture coordinate generation to determine whether each fragment is lit.
+*/
 class ShadowMap: public Effect
 {
 private:
@@ -26,15 +32,23 @@ private:
        const Scene &scene;
        const Light &light;
        Framebuffer fbo;
-public:
+       unsigned unit;
        Texture2D depth_buf;
-private:
        Vector3 target;
        float radius;
 
 public:
        ShadowMap(unsigned, const Scene &, const Light &);
+
+       /** Sets the ShadowMap target point and radius.  The transformation matrix is
+       computed so that a sphere with the specified parameters will be completely
+       covered by the ShadowMap. */
        void set_target(const Vector3 &, float);
+
+       /** Sets the texture unit to bind the shadow map to during the rendering
+       phase.  The default is texture unit 3. */
+       void set_texture_unit(unsigned);
+
        virtual void prepare();
        virtual void cleanup();
 };