FBO.cc 10.1 KB
Newer Older
Jan Möbius's avatar
Jan Möbius committed
1
2
3
4
5
6
7
8
9
//=============================================================================
//
//  CLASS FBO - IMPLEMENTATION
//
//=============================================================================

//== INCLUDES =================================================================

#include "FBO.hh"
10
#include "GLState.hh"
11
#include "GLError.hh"
Jan Möbius's avatar
Jan Möbius committed
12
13
14
15
16
17
18
19

//== NAMESPACES ===============================================================

namespace ACG
{

//== IMPLEMENTATION ==========================================================

20
21
22


FBO::FBO()
23
: fbo_(0), depthbuffer_(0), stencilbuffer_(0), width_(0), height_(0), samples_(0), fixedsamplelocation_(GL_TRUE), prevFbo_(0)
24
25
26
{
}

Jan Möbius's avatar
Jan Möbius committed
27
28
29
FBO::
~FBO()
{
30
31
  // delete framebuffer object
  if(fbo_)
Jan Möbius's avatar
Jan Möbius committed
32
    glDeleteFramebuffersEXT( 1, &fbo_ );
33
34
35

  // delete render buffer
  if(depthbuffer_)
Jan Möbius's avatar
Jan Möbius committed
36
    glDeleteRenderbuffersEXT(1, &depthbuffer_);
37
38
39

  // delete stencil buffer
  if(stencilbuffer_)
40
    glDeleteRenderbuffersEXT(1, &stencilbuffer_);
41
42
43

  for (size_t i = 0; i < internalTextures_.size(); ++i)
    glDeleteTextures(1, &internalTextures_[i].id);
Jan Möbius's avatar
Jan Möbius committed
44
45
46
47
48
49
50
51
}

//-----------------------------------------------------------------------------

void
FBO::
init()
{
52
53
54
55
56
  // Create framebuffer object
  if (!checkExtensionSupported("GL_EXT_framebuffer_object")) {
    std::cerr << "Framebuffer object not supported! " << std::endl;
    exit( 1 );
  }
Jan Möbius's avatar
Jan Möbius committed
57

58
59
60
  // test whether fbo hasn't been created before
  if(!fbo_)
    glGenFramebuffersEXT( 1, &fbo_ );
Jan Möbius's avatar
Jan Möbius committed
61

62
63
  // check status
  checkFramebufferStatus();
Jan Möbius's avatar
Jan Möbius committed
64

65
66
  // unbind fbo
  unbind();
Jan Möbius's avatar
Jan Möbius committed
67
68
69
70
71
72
}

//-----------------------------------------------------------------------------

void
FBO::
73
attachTexture2D( GLenum _attachment, GLuint _texture, GLenum _target )
Jan Möbius's avatar
Jan Möbius committed
74
{
75
76
  // bind fbo
  bind();
Jan Möbius's avatar
Jan Möbius committed
77

78
  // add texture to frame buffer object
79
80
81
  glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, _attachment, _target, _texture, 0 );

  checkGLError();
Jan Möbius's avatar
Jan Möbius committed
82

83
84
  // check status
  checkFramebufferStatus();
Jan Möbius's avatar
Jan Möbius committed
85

86
87
88
89
  // unbind fbo
  unbind();

  // track texture id
90
  attachments_[_attachment] = std::pair<GLuint, GLenum>(_texture, _target);
91
92
93
94
95
96
97
98
99
100
}

//-----------------------------------------------------------------------------

void FBO::attachTexture2D( GLenum _attachment, GLsizei _width, GLsizei _height, GLuint _internalFmt, GLenum _format, GLint _wrapMode /*= GL_CLAMP*/, GLint _minFilter /*= GL_LINEAR*/, GLint _magFilter /*= GL_LINEAR*/ )
{
  // gen texture id
  GLuint texID;
  glGenTextures(1, &texID);

101
  GLenum target = samples_ ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
102
103
104
105
106
107

  // store texture id in internal array
  RenderTexture intID;
  intID.id = texID;
  intID.internalFormat = _internalFmt;
  intID.format = _format;
108
  intID.target = target;
109
110
111
112
  internalTextures_.push_back(intID);


  // specify texture
113
114
115
116
  glBindTexture(target, texID);

  glTexParameteri(target, GL_TEXTURE_WRAP_S, _wrapMode);
  glTexParameteri(target, GL_TEXTURE_WRAP_T, _wrapMode);
117

118
119
120
121
122
123
124
125
  if (!samples_)
  {
    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, _minFilter);
    glTexParameteri(target, GL_TEXTURE_MAG_FILTER, _magFilter);
    glTexImage2D(target, 0, _internalFmt, _width, _height, 0, _format, GL_FLOAT, 0);
  }
  else
    glTexImage2DMultisample(target, samples_, _internalFmt, _width, _height, fixedsamplelocation_);
126

127
  checkGLError();
128
129
130
131

  width_ = _width;
  height_ = _height;

132
  glBindTexture(target, 0);
133
134

  // attach
135
  attachTexture2D(_attachment, texID, target);
136
137
138
139
140
141
142
143
144
145
}

//-----------------------------------------------------------------------------

void FBO::attachTexture2DDepth( GLsizei _width, GLsizei _height, GLuint _internalFmt /*= GL_DEPTH_COMPONENT32*/, GLenum _format /*= GL_DEPTH_COMPONENT */ )
{
  // gen texture id
  GLuint texID;
  glGenTextures(1, &texID);

146
147
  GLenum target = samples_ ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;

148
149
150
151
152
  // store texture id in internal array
  RenderTexture intID;
  intID.id = texID;
  intID.internalFormat = _internalFmt;
  intID.format = _format;
153
  intID.target = target;
154
155
156
157
  internalTextures_.push_back(intID);


  // specify texture
158
  glBindTexture(target, texID);
159

160
161
  glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
162

163
164
165
166
167
168
169
170
  if (!samples_)
  {
    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexImage2D(target, 0, _internalFmt, _width, _height, 0, _format, _format == GL_DEPTH_STENCIL ? GL_UNSIGNED_INT_24_8 : GL_FLOAT, 0);
  }
  else
    glTexImage2DMultisample(target, samples_, _internalFmt, _width, _height, fixedsamplelocation_);
171

172
  checkGLError();
173
174
175
176

  width_ = _width;
  height_ = _height;

177
  glBindTexture(target, 0);
178
179

  // attach
180
  attachTexture2D(GL_DEPTH_ATTACHMENT, texID, target);
Jan Möbius's avatar
Jan Möbius committed
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
}

//-----------------------------------------------------------------------------

void
FBO::
addDepthBuffer( GLuint _width, GLuint _height )
{
  // create renderbuffer
  glGenRenderbuffersEXT(1, &depthbuffer_);

  // bind renderbuffer
  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer_);

  // malloc
  glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, _width, _height);

  // attach to framebuffer object
  if ( bind() )
200
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthbuffer_);
Jan Möbius's avatar
Jan Möbius committed
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225

  // check status
  checkFramebufferStatus();

  // normal render mode
  unbind();
}

//-----------------------------------------------------------------------------

void
FBO::
addStencilBuffer( GLuint _width, GLuint _height )
{
  // create renderbuffer
  glGenRenderbuffersEXT(1, &stencilbuffer_);

  // bind renderbuffer
  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencilbuffer_);

  // malloc
  glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX, _width, _height);

  // attach to framebuffer object
  if ( bind() )
226
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, stencilbuffer_);
Jan Möbius's avatar
Jan Möbius committed
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242

  // check status
  checkFramebufferStatus();

  // normal render mode
  unbind();
}



//-----------------------------------------------------------------------------

bool
FBO::
bind()
{
243
244
  if ( !fbo_ )
    return false;
Jan Möbius's avatar
Jan Möbius committed
245

246
247
248
  // save previous fbo id
  glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (GLint*)&prevFbo_);

249
250
  // bind framebuffer object
  ACG::GLState::bindFramebuffer( GL_FRAMEBUFFER_EXT, fbo_ );
Jan Möbius's avatar
Jan Möbius committed
251

252
  return true;
Jan Möbius's avatar
Jan Möbius committed
253
254
255
256
257
258
259
260
}

//-----------------------------------------------------------------------------

void
FBO::
unbind()
{
261
  //set to normal rendering
262
  ACG::GLState::bindFramebuffer( GL_FRAMEBUFFER_EXT, prevFbo_ );
Jan Möbius's avatar
Jan Möbius committed
263
264
265
266
267
268
269
270
}

//-----------------------------------------------------------------------------

bool
FBO::
checkFramebufferStatus()
{
271
272
  GLenum status;
  status = ( GLenum ) glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
Jan Möbius's avatar
Jan Möbius committed
273
  //std::cout << "Framebuffer status: " << status << std::endl;
274
275
276
  switch ( status )
  {
    case GL_FRAMEBUFFER_COMPLETE_EXT:
Jan Möbius's avatar
Jan Möbius committed
277
      //std::cout << "Framebuffer ok\n";
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
      break;
    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
      std::cout << " Framebuffer incomplete attachment\n";
      break;
    case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
      std::cout << "Unsupported framebuffer format\n";
      break;
    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
      std::cout << "Framebuffer incomplete, missing attachment\n";
      break;
    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
      std::cout <<  "Framebuffer incomplete, attached images must have same dimensions\n";
      break;
    case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
      std::cout << "Framebuffer incomplete, attached images must have same format\n";
      break;
    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
      std::cout << "Framebuffer incomplete, missing draw buffer\n";
      break;
    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
      std::cout << "Framebuffer incomplete, missing read buffer\n";
      break;
    default:
      std::cout << "Unhandled case\n";
      break;
  }

  return ( status == GL_FRAMEBUFFER_COMPLETE_EXT );
}

//-----------------------------------------------------------------------------

GLuint FBO::getAttachment( GLenum _attachment )
{
312
  return attachments_[_attachment].first;
313
314
315
316
}

//-----------------------------------------------------------------------------

317
void FBO::resize( GLsizei _width, GLsizei _height, bool _forceResize )
318
{
319
  if (_width != width_ ||_height != height_ || _forceResize)
320
  {
321
    bool reattachTextures = false;
322
323
324

    // resize every texture stored in internal array
    for (size_t i = 0; i < internalTextures_.size(); ++i)
Jan Möbius's avatar
Jan Möbius committed
325
    {
326
327
      RenderTexture* rt = &internalTextures_[i];

328
329
330
331
332
333
334
335
336
337
338
339
340
341
      // check if we have to convert to multisampling
      if (rt->target != GL_TEXTURE_2D_MULTISAMPLE && samples_ > 0)
      {
        rt->target = GL_TEXTURE_2D_MULTISAMPLE;
        reattachTextures = true;
      }


      glBindTexture(rt->target, rt->id);

      if (!samples_)
        glTexImage2D(rt->target, 0, rt->internalFormat, _width, _height, 0, rt->format, rt->format == GL_DEPTH_STENCIL ? GL_UNSIGNED_INT_24_8 : GL_FLOAT, 0);
      else
        glTexImage2DMultisample(rt->target, samples_, rt->internalFormat, _width, _height, fixedsamplelocation_);
Jan Möbius's avatar
Jan Möbius committed
342
343
    }

344
345
346
347
    // store new size
    width_ = _width;
    height_ = _height;

348
349
350
351
352
353
354
355
356
357
358


    if (reattachTextures)
    {
      for (AttachmentList::iterator it = attachments_.begin(); it != attachments_.end(); ++it)
      {
        attachTexture2D( it->first, it->second.first, it->second.second );
      }
    }


359
360
361
362
363
364
365
366
367
    glBindTexture(GL_TEXTURE_2D, 0);

  }

}

GLuint FBO::getFboID()
{
  return fbo_;
Jan Möbius's avatar
Jan Möbius committed
368
369
}

370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
void FBO::setMultisampling( GLsizei _samples, GLboolean _fixedsamplelocations /*= GL_TRUE*/ )
{
  // clamp sample count to max supported
  GLint maxSamples;
  glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);

  if (_samples > maxSamples) _samples = maxSamples;

  // issue texture reloading when params changed
  bool reloadTextures = (samples_ != _samples || fixedsamplelocation_ != _fixedsamplelocations);
    
  samples_ = _samples;
  fixedsamplelocation_ = _fixedsamplelocations;


  // force a texture reloading to apply new multisampling
  if (reloadTextures)
    resize(width_, height_, true);
}

Jan Möbius's avatar
Jan Möbius committed
390
391
392
393

//=============================================================================
} // namespace ACG
//=============================================================================