FrameBufferObject.hh 14 KB
Newer Older
1
2
3
4
5
/***********************************************************************
 * Copyright 2011-2012 Computer Graphics Group RWTH Aachen University. *
 * All rights reserved.                                                *
 * Distributed under the terms of the MIT License (see LICENSE.TXT).   *
 **********************************************************************/
Robert Menzel's avatar
Robert Menzel committed
6

7
8
#ifndef ACGL_OPENGL_OBJECTS_FRAMEBUFFEROBJECT_HH
#define ACGL_OPENGL_OBJECTS_FRAMEBUFFEROBJECT_HH
Robert Menzel's avatar
Robert Menzel committed
9

Robert Menzel's avatar
Robert Menzel committed
10
/**
11
12
 * This FrameBufferObject class encapsulates an OpenGL frame buffer object (FBO).
 * A FrameBufferObject is a target for rendering and thus consists of different "layers":
13
14
15
16
17
 *
 * one or no depthbuffer
 * one or no stencilbuffer
 * one (OpenGL ES) to many (hardware dependent limit) colorbuffers
 *
18
 * These buffers get attached to the FrameBufferObject.
19
20
21
22
23
24
25
26
 *
 * 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
27

28
#include <ACGL/Base/Macros.hh>
29
#include <ACGL/Utils/StringHelpers.hh>
Robert Menzel's avatar
Robert Menzel committed
30
31
#include <ACGL/OpenGL/GL.hh>
#include <ACGL/OpenGL/Tools.hh>
32
#include <ACGL/OpenGL/Debug.hh>
Robert Menzel's avatar
Robert Menzel committed
33
34
#include <ACGL/OpenGL/Objects/RenderBuffer.hh>
#include <ACGL/OpenGL/Objects/Texture.hh>
Robert Menzel's avatar
Robert Menzel committed
35
#include <ACGL/OpenGL/Data/LocationMappings.hh>
Robert Menzel's avatar
Robert Menzel committed
36

37
#include <vector>
38
#include <map>
Robert Menzel's avatar
Robert Menzel committed
39
40

namespace ACGL{
Robert Menzel's avatar
Robert Menzel committed
41
namespace OpenGL{
Robert Menzel's avatar
Robert Menzel committed
42

43
class FrameBufferObject
Robert Menzel's avatar
Robert Menzel committed
44
{
45
    ACGL_NOT_COPYABLE(FrameBufferObject)
46

Robert Menzel's avatar
Robert Menzel committed
47
48
49
50
    // ==================================================================================================== \/
    // ============================================================================================ STRUCTS \/
    // ==================================================================================================== \/
public:
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    //! defines a clear color per color buffer
    struct ClearColor {
        ClearColor() {
            mType = Float;
            mColor.floatColor[0] = mColor.floatColor[1] = mColor.floatColor[2] = mColor.floatColor[3] = 0.0f;
        }

        enum Type { Integer, UnsignedInteger, Float };
        union Data {
            GLint   intColor[4];
            GLuint  uintColor[4];
            GLfloat floatColor[4];
        } mColor;
        Type mType; // defines which of the data types of the union to use
    };
66
67
68
69
70
71
72
73
74

    //! An attachment can be a texture or a render buffer
    struct Attachment
    {
        std::string             name;         // user defined name that matches the fragment shader out
        ConstSharedTextureBase  texture;      // attached color texture, or:
        ConstSharedRenderBuffer renderBuffer; // attached renderbuffer - only this or the texture should be set!
        GLuint                  location;     // the frag data location that maps to this attachment
        Image                   image;        // in case of a texture the image will define which part of the texture to use
75
        ClearColor              clearColor;   // clear color of the attachement
Robert Menzel's avatar
Robert Menzel committed
76
77
78
79
80
81
82
83
    };

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

84
85
86
    // ========================================================================================================= \/
    // ============================================================================================ CONSTRUCTORS \/
    // ========================================================================================================= \/
Robert Menzel's avatar
Robert Menzel committed
87
public:
88
    FrameBufferObject(void)
89
    :   mObjectName(0),
Robert Menzel's avatar
Robert Menzel committed
90
91
92
        mColorAttachments(),
        mDepthAttachment()
    {
Robert Menzel's avatar
Robert Menzel committed
93
        mObjectName = 0;
94
        glGenFramebuffers(1, &mObjectName);
95
        mDepthAttachment.texture      = ConstSharedTextureBase();
96
        mDepthAttachment.renderBuffer = ConstSharedRenderBuffer();
Robert Menzel's avatar
Robert Menzel committed
97
        mDepthAttachment.name     = ""; // not useful here
Robert Menzel's avatar
Robert Menzel committed
98
        mDepthAttachment.location =  0; // not useful here
Robert Menzel's avatar
Robert Menzel committed
99
100
    }

101
    virtual ~FrameBufferObject(void)
Robert Menzel's avatar
Robert Menzel committed
102
    {
103
        // buffer 0 will get ignored by OpenGL
104
        glDeleteFramebuffers(1, &mObjectName);
Robert Menzel's avatar
Robert Menzel committed
105
106
    }

107
108
109
110
111
112
113
114
115
116
117
118
119
120
    // ===================================================================================================== \/
    // =========================================================================================== KHR_DEBUG \/
    // ===================================================================================================== \/
public:
    // Sets and gets a label visible inside of a OpenGL debugger if KHR_debug is supported at runtime *and*
    // if ACGL_OPENGL_DEBUGGER_SUPPORT was defined during compile time. Does nothing otherwise!
#ifdef ACGL_OPENGL_DEBUGGER_SUPPORT
    void setObjectLabel( const std::string &_label ) { setObjectLabelT<GL_FRAMEBUFFER>(getObjectName(),_label); }
    std::string getObjectLabel() { return getObjectLabelT<GL_FRAMEBUFFER>(getObjectName()); }
#else
    void setObjectLabel( const std::string & ) {}
    std::string getObjectLabel() { return ""; }
#endif

121
122
123
    // ==================================================================================================== \/
    // ============================================================================================ GETTERS \/
    // ==================================================================================================== \/
Robert Menzel's avatar
Robert Menzel committed
124
public:
125
    inline       GLuint         getObjectName       (void) const { return mObjectName; }
Robert Menzel's avatar
Robert Menzel committed
126
127
128
    inline const AttachmentVec& getColorAttachments (void) const { return mColorAttachments; }
    inline const Attachment&    getDepthAttachment  (void) const { return mDepthAttachment;  }

129
130
131
    // ===================================================================================================== \/
    // ============================================================================================ WRAPPERS \/
    // ===================================================================================================== \/
Robert Menzel's avatar
Robert Menzel committed
132
public:
133
134
     int_t getColorAttachmentIndexByName(const std::string& _name) const;

135
     void validate (void) const;
136

137
    /**
138
139
     * Per default a FrameBufferObject gets used for read/write operations, but we can
     * bind two different FrameBufferObjects for these operations!
140
     */
141
    inline void bind(GLenum _type = GL_FRAMEBUFFER) const
Robert Menzel's avatar
Robert Menzel committed
142
    {
143
        glBindFramebuffer(_type, mObjectName);
Robert Menzel's avatar
Robert Menzel committed
144
145
    }

Robert Menzel's avatar
Robert Menzel committed
146
    //! let OpenGL validate the completeness
Robert Menzel's avatar
Robert Menzel committed
147
    bool isFrameBufferObjectComplete() const;
148

Robert Menzel's avatar
Robert Menzel committed
149
150
151
152
    /*
     * Attach another RenderBuffer as a render target. If the name already exists the old target will get replaced.
     */
    inline bool attachColorRenderBuffer(const std::string &_name, const ConstSharedRenderBuffer& _renderBuffer)
Robert Menzel's avatar
Robert Menzel committed
153
    {
154
        Attachment a = {_name, SharedTextureBase(), _renderBuffer, 0xFFFFFFFF, Image(), ClearColor()};
Robert Menzel's avatar
Robert Menzel committed
155
        return attachColorAttachment( a );
Robert Menzel's avatar
Robert Menzel committed
156
157
    }

158
    inline bool attachColorTexture(const std::string &_name, const ConstSharedTextureBase& _texture, const Image _image = Image() )
Robert Menzel's avatar
Robert Menzel committed
159
    {
160
        Attachment a = {_name, _texture, SharedRenderBuffer(), 0xFFFFFFFF, _image, ClearColor()};
Robert Menzel's avatar
Robert Menzel committed
161
        return attachColorAttachment( a );
162
163
    }

Robert Menzel's avatar
Robert Menzel committed
164
    inline bool attachColorRenderBuffer(const std::string &_name, const ConstSharedRenderBuffer& _renderBuffer, GLuint _location )
165
    {
166
        Attachment a = {_name, SharedTextureBase(), _renderBuffer, _location, Image(), ClearColor()};
Robert Menzel's avatar
Robert Menzel committed
167
        return attachColorAttachment( a );
168
169
    }

170
    inline bool attachColorTexture(const std::string &_name, const ConstSharedTextureBase& _texture, GLuint _location, const Image _image = Image() )
171
    {
172
        Attachment a = {_name, _texture, SharedRenderBuffer(), _location, _image, ClearColor()};
Robert Menzel's avatar
Robert Menzel committed
173
        return attachColorAttachment( a );
Robert Menzel's avatar
Robert Menzel committed
174
175
    }

176
177
178
    // if the location within the attachment is larger than the possible number of attachments,
    // attachColorAttachment will try to find a non-colliding attachment point.
    // this can be used to say "i don't care about the actual attachment number used"
Robert Menzel's avatar
Robert Menzel committed
179
180
181
182
    bool attachColorAttachment( const Attachment &_attachment );

    void remapAttachments();

183
    inline bool setDepthRenderBuffer(const ConstSharedRenderBuffer& _renderBuffer)
Robert Menzel's avatar
Robert Menzel committed
184
    {
Robert Menzel's avatar
Robert Menzel committed
185
        bind();
186
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffer->getObjectName() );
Robert Menzel's avatar
Robert Menzel committed
187
        #if (ACGL_OPENGLES_VERSION == 20)
Robert Menzel's avatar
Robert Menzel committed
188
189
            if( _renderBuffer->getInternalFormat() == GL_DEPTH24_STENCIL8_OES ||
                _renderBuffer->getInternalFormat() == GL_DEPTH_STENCIL_OES)
190
                glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderBuffer->getObjectName() );
Robert Menzel's avatar
Robert Menzel committed
191
192
193
        #else
            if( _renderBuffer->getInternalFormat() == GL_DEPTH24_STENCIL8 ||
                _renderBuffer->getInternalFormat() == GL_DEPTH_STENCIL)
194
                glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderBuffer->getObjectName() );
Robert Menzel's avatar
Robert Menzel committed
195
196
197
198
199
        #endif
        mDepthAttachment.renderBuffer = _renderBuffer;
        return true;
    }

200
201
    //! todo: support mipmap levels
    inline bool setDepthTexture(const ConstSharedTextureBase& _texture)
Robert Menzel's avatar
Robert Menzel committed
202
    {
Robert Menzel's avatar
Robert Menzel committed
203
        bind();
204
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, _texture->getTarget(), _texture->getObjectName(), 0);
Robert Menzel's avatar
Robert Menzel committed
205
        #if (ACGL_OPENGLES_VERSION == 20)
Robert Menzel's avatar
Robert Menzel committed
206
207
            if( _texture->getInternalFormat() == GL_DEPTH24_STENCIL8_OES ||
                _texture->getInternalFormat() == GL_DEPTH_STENCIL_OES)
208
                glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, _texture->getTarget(), _texture->getObjectName(), 0);
Robert Menzel's avatar
Robert Menzel committed
209
210
211
        #else
            if( _texture->getInternalFormat() == GL_DEPTH24_STENCIL8 ||
                _texture->getInternalFormat() == GL_DEPTH_STENCIL)
212
                glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, _texture->getTarget(), _texture->getObjectName(), 0);
Robert Menzel's avatar
Robert Menzel committed
213
214
215
216
217
        #endif
        mDepthAttachment.texture = _texture;
        return true;
    }

218
    //! x,y coordinate is the FBO size in pixels, z coordinate the number of color attachments. x,y are both 0 if the FBO has no useful size
219
    //! todo: support mipmap levels
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
    glm::uvec3 getSize() const
    {
        glm::uvec3 size;

        if (mDepthAttachment.texture) {
            // use the size of the depth texture
            size = mDepthAttachment.texture->getSize();
        } else if (mDepthAttachment.renderBuffer) {
            // use the size of the depth render buffer
            size = glm::uvec3( mDepthAttachment.renderBuffer->getSize(), 0 );
        } else if ( mColorAttachments.size() > 0 ) {
            if (mColorAttachments[0].texture) {
                // use the size of the first texture:
                size = mColorAttachments[0].texture->getSize();
            } else if (mColorAttachments[0].renderBuffer) {
                // use the size of the first renderBuffer:
                size = glm::uvec3( mColorAttachments[0].renderBuffer->getSize(), 0 );
            }
        } else {
            size = glm::uvec3(0);
        }

242
        size.z = (glm::uint) mColorAttachments.size();
243
244
245
        return size;
    }

246
247
248
249
250
251
252
    // =================================================================================================== \/
    // =========================================================================================== METHODS \/
    // =================================================================================================== \/
public:
    //! sets the attachment locations of this FBO where they match the names specified in _locationMappings
    void setAttachmentLocations(ConstSharedLocationMappings _locationMappings);

Robert Menzel's avatar
Robert Menzel committed
253
    //! get a list of attachment locations and names that can be used to set up a ShaderProgram
254
    SharedLocationMappings getAttachmentLocations() const;
255

256
257
    //! returns the current contents of the default FrameBuffer
    //! the format of the returned TextureData will be GL_RGB, the type will be GL_UNSIGNED_INT
258
    //! _readBuffer = GL_INVALID_ENUM will read out the default read buffer
259
260
    static SharedTextureData getImageData(GLsizei _width, GLsizei _height, GLint _x = 0, GLint _y = 0, GLenum _readBuffer = GL_INVALID_ENUM);

261
262
263
    //! get the part of the framebuffer thats part of the current viewport
    static SharedTextureData getImageData();

264
265
266
267
268
269
270
    //
    // clear buffer functions:
    //

    //! clear only the depth buffer:
    void clearDepthBuffer();

271
#if ((ACGL_OPENGLES_VERSION >= 30) || (ACGL_OPENGL_VERSION >= 20))
272
273
274
275
276
    //! clear one specific color buffer:
    void clearBuffer( const std::string &_name );

    //! clear all buffers, color and depth:
    void clearBuffers();
277
#endif
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292

    //! sets the clear color for one buffer:
    void setClearColor( const std::string &_name, const glm::vec4 &_color );
    //! sets the clear color for one buffer:
    void setClearColor( const std::string &_name, const glm::ivec4 &_color );
    //! sets the clear color for one buffer:
    void setClearColor( const std::string &_name, const glm::uvec4 &_color );

    //! sets the clear color for all color buffers:
    void setClearColor( const glm::vec4 &_color );
    //! sets the clear color for all color buffers:
    void setClearColor( const glm::ivec4 &_color );
    //! sets the clear color for all color buffers:
    void setClearColor( const glm::uvec4 &_color );

293
294
295
    // =================================================================================================== \/
    // ============================================================================================ FIELDS \/
    // =================================================================================================== \/
Robert Menzel's avatar
Robert Menzel committed
296
protected:
297
    GLuint        mObjectName;
Robert Menzel's avatar
Robert Menzel committed
298
    AttachmentVec mColorAttachments;
Robert Menzel's avatar
Robert Menzel committed
299
    Attachment    mDepthAttachment;   // depth and stencil are combined
Robert Menzel's avatar
Robert Menzel committed
300
301
};

Robert Menzel's avatar
Robert Menzel committed
302
ACGL_SMARTPOINTER_TYPEDEFS(FrameBufferObject)
Robert Menzel's avatar
Robert Menzel committed
303
304

} // OpenGL
Robert Menzel's avatar
Robert Menzel committed
305
306
} // ACGL

307
#endif // ACGL_OPENGL_OBJECTS_FRAMEBUFFEROBJECT_HH