FrameBuffer.hh 9.27 KB
Newer Older
Robert Menzel's avatar
Robert Menzel committed
1 2 3 4 5
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011, Computer Graphics Group RWTH Aachen University         //
// All rights reserved.                                                       //
////////////////////////////////////////////////////////////////////////////////

6 7
#ifndef ACGL_OPENGL_OBJECTS_FRAMEBUFFER_HH
#define ACGL_OPENGL_OBJECTS_FRAMEBUFFER_HH
Robert Menzel's avatar
Robert Menzel committed
8

9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * This FrameBuffer class encapsulates an OpenGL frame buffer object (FBO).
 * A FrameBuffer is a target for rendering and thus consists of different "layers":
 *
 * one or no depthbuffer
 * one or no stencilbuffer
 * one (OpenGL ES) to many (hardware dependent limit) colorbuffers
 *
 * These buffers get attached to the FrameBuffer.
 *
 * There exists one system-provided frame buffer object for rendering to the screen
 * and optionaly multiple user defined frame buffer objects for offscreen rendering.
 *
 * This class does not encapsulate the system-provided FBO.
 */

#include <ACGL/ACGL.hh>
Robert Menzel's avatar
Robert Menzel committed
26

27 28
#include <ACGL/Base/Macros.hh>
#include <ACGL/Base/StringOperations.hh>
Robert Menzel's avatar
Robert Menzel committed
29 30 31 32 33
#include <ACGL/OpenGL/GL.hh>
#include <ACGL/OpenGL/Tools.hh>
#include <ACGL/OpenGL/Objects/RenderBuffer.hh>
#include <ACGL/OpenGL/Objects/Texture.hh>

34
#include <vector>
Robert Menzel's avatar
Robert Menzel committed
35
#include <tr1/memory>
Robert Menzel's avatar
Robert Menzel committed
36 37

namespace ACGL{
Robert Menzel's avatar
Robert Menzel committed
38
namespace OpenGL{
Robert Menzel's avatar
Robert Menzel committed
39 40 41

class FrameBuffer
{
42
    ACGL_NOT_COPYABLE(FrameBuffer)
43

Robert Menzel's avatar
Robert Menzel committed
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
    // =================================================================================================== \/
    // ============================================================================================ STATIC \/
    // =================================================================================================== \/
private:
    static GLuint msBuffers[8];

    // ==================================================================================================== \/
    // ============================================================================================ STRUCTS \/
    // ==================================================================================================== \/
public:
    //! An attachment can be a texture or a render buffer
    struct Attachment
    {
        std::string name;
        SharedTexture texture;
        SharedRenderBuffer renderBuffer;
    };

    // ===================================================================================================== \/
    // ============================================================================================ TYPEDEFS \/
    // ===================================================================================================== \/
public:
    typedef std::vector< Attachment > AttachmentVec;

68 69 70
    // ========================================================================================================= \/
    // ============================================================================================ CONSTRUCTORS \/
    // ========================================================================================================= \/
Robert Menzel's avatar
Robert Menzel committed
71 72 73 74 75 76 77 78
public:
    FrameBuffer(GLsizei _width, GLsizei _height)
    :   mContext(0),
        mDrawBuffers(0),
        mColorAttachments(),
        mDepthAttachment()
    {
        glGenFramebuffers(1, &mContext);
79 80 81 82
        if (openGLCriticalErrorOccured() ) {
            ACGL::Utils::error() << "could not generate framebuffer!" << std::endl;
            return;
        }
Robert Menzel's avatar
Robert Menzel committed
83 84 85 86 87 88 89
        mDepthAttachment.name = "";
        mDepthAttachment.texture = SharedTexture();
        mDepthAttachment.renderBuffer = SharedRenderBuffer();
    }

    virtual ~FrameBuffer(void)
    {
90 91
        // buffer 0 will get ignored by OpenGL
        glDeleteFramebuffers(1, &mContext);
Robert Menzel's avatar
Robert Menzel committed
92 93
    }

94 95 96
    // ==================================================================================================== \/
    // ============================================================================================ GETTERS \/
    // ==================================================================================================== \/
Robert Menzel's avatar
Robert Menzel committed
97 98 99 100 101
public:
    inline       GLuint         getContext          (void) const { return mContext;          }
    inline const AttachmentVec& getColorAttachments (void) const { return mColorAttachments; }
    inline const Attachment&    getDepthAttachment  (void) const { return mDepthAttachment;  }

102 103 104
    // ===================================================================================================== \/
    // ============================================================================================ WRAPPERS \/
    // ===================================================================================================== \/
Robert Menzel's avatar
Robert Menzel committed
105
public:
106 107
     int_t getColorAttachmentIndexByName(const std::string& _name) const;

108 109
     void validate( void ) const;

110 111 112 113
    /**
     * Per default a FrameBuffer gets used for read/write operations, but we can
     * bind two different FrameBuffers for these operations!
     */
114
    inline void bind(GLenum _type = GL_FRAMEBUFFER) const
Robert Menzel's avatar
Robert Menzel committed
115
    {
116 117
        glBindFramebuffer(_type, mContext);
        openGLRareError(); // glBindFramebuffer can only fail if the contect is no valid FBO which shouldn't happen using this framework
Robert Menzel's avatar
Robert Menzel committed
118 119
    }

120
    inline void bindAsRenderTarget(GLenum _type = GL_FRAMEBUFFER) const
Robert Menzel's avatar
Robert Menzel committed
121
    {
122 123 124
        glBindFramebuffer(_type, mContext);
        glDrawBuffers(mDrawBuffers, msBuffers);
        openGLRareError();
Robert Menzel's avatar
Robert Menzel committed
125 126
    }

127
    inline void bindAsRenderTarget(GLint _x, GLint _y, GLsizei _w, GLsizei _h, GLenum _type = GL_FRAMEBUFFER) const
Robert Menzel's avatar
Robert Menzel committed
128
    {
129 130 131
        glBindFramebuffer(_type, mContext);
        glDrawBuffers(mDrawBuffers, msBuffers);
        openGLRareError();
Robert Menzel's avatar
Robert Menzel committed
132 133
    }

134 135 136 137 138 139 140 141 142 143
    inline bool isFrameBufferComplete(void) const
    {
        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        {
            Utils::error() << "Failed to make complete FrameBuffer object: " << (glCheckFramebufferStatus(GL_FRAMEBUFFER)) << std::endl;
            return false;
        }
        return true;
    }

144
    inline bool attachColorRenderBuffer(const std::string _name, const SharedRenderBuffer& _renderBuffer)
Robert Menzel's avatar
Robert Menzel committed
145 146
    {
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + mDrawBuffers, GL_RENDERBUFFER, _renderBuffer->getContext());
147 148 149 150
        if (openGLCommonErrorOccured()) {
            Utils::error() << "Attaching of texture to the FBO failed" << std::endl;
            return false;
        }
Robert Menzel's avatar
Robert Menzel committed
151
        mDrawBuffers++;
152
        Attachment attachment = {_name, SharedTexture(), _renderBuffer};
Robert Menzel's avatar
Robert Menzel committed
153 154 155 156
        mColorAttachments.push_back(attachment);
        return true;
    }

157
    inline bool attachColorTexture(const std::string _name, const SharedTexture& _texture)
Robert Menzel's avatar
Robert Menzel committed
158 159
    {
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + mDrawBuffers, _texture->getTarget(), _texture->getContext(), 0);
160 161 162 163
        if (openGLCommonErrorOccured()) {
            Utils::error() << "Attaching of texture to the FBO failed" << std::endl;
            return false;
        }
Robert Menzel's avatar
Robert Menzel committed
164
        mDrawBuffers++;
165
        Attachment attachment = {_name, _texture, SharedRenderBuffer()};
Robert Menzel's avatar
Robert Menzel committed
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
        mColorAttachments.push_back(attachment);
        return true;
    }

    inline bool setDepthRenderBuffer(const SharedRenderBuffer& _renderBuffer)
    {
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffer->getContext());
        #ifdef OPENGL_ES
            if( _renderBuffer->getInternalFormat() == GL_DEPTH24_STENCIL8_OES ||
                _renderBuffer->getInternalFormat() == GL_DEPTH_STENCIL_OES)
                glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderBuffer->getContext());
        #else
            if( _renderBuffer->getInternalFormat() == GL_DEPTH24_STENCIL8 ||
                _renderBuffer->getInternalFormat() == GL_DEPTH_STENCIL)
                glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderBuffer->getContext());
        #endif
        mDepthAttachment.renderBuffer = _renderBuffer;
        return true;
    }

    inline bool setDepthTexture(const SharedTexture& _texture)
    {
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, _texture->getTarget(), _texture->getContext(), 0);
        #ifdef OPENGL_ES
            if( _texture->getInternalFormat() == GL_DEPTH24_STENCIL8_OES ||
                _texture->getInternalFormat() == GL_DEPTH_STENCIL_OES)
                glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, _texture->getTarget(), _texture->getContext(), 0);
        #else
            if( _texture->getInternalFormat() == GL_DEPTH24_STENCIL8 ||
                _texture->getInternalFormat() == GL_DEPTH_STENCIL)
                glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, _texture->getTarget(), _texture->getContext(), 0);
        #endif
        mDepthAttachment.texture = _texture;
        return true;
    }

202 203 204
    // =================================================================================================== \/
    // ============================================================================================ FIELDS \/
    // =================================================================================================== \/
Robert Menzel's avatar
Robert Menzel committed
205 206 207 208
protected:
    GLuint        mContext;
    GLsizei       mDrawBuffers;
    AttachmentVec mColorAttachments;
209
    Attachment    mDepthAttachment;  // depth and stencil are combined
Robert Menzel's avatar
Robert Menzel committed
210 211
};

212
ACGL_SHARED_TYPEDEF(FrameBuffer)
Robert Menzel's avatar
Robert Menzel committed
213 214

} // OpenGL
Robert Menzel's avatar
Robert Menzel committed
215 216
} // ACGL

217
#endif // ACGL_OPENGL_OBJECTS_FRAMEBUFFER_HH