00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #ifndef INVT_HAVE_LIBGL
00047
00048 #include "Robots/LoBot/ui/LoRenderBuffer.H"
00049 #include "Robots/LoBot/misc/LoExcept.H"
00050
00051 namespace lobot {
00052
00053 RenderBuffer::RenderBuffer(int, int)
00054 : m_width(0), m_height(0),
00055 m_size(0), m_cache(0), m_dirty(false),
00056 m_fbo(0), m_rbo(0)
00057 {
00058 throw missing_libs(MISSING_OPENGL) ;
00059 }
00060
00061 void RenderBuffer::setup(){}
00062 const unsigned char* RenderBuffer::pixels() const {return 0 ;}
00063 void RenderBuffer::to_screen(){}
00064 void RenderBuffer::clean_up(){}
00065 RenderBuffer::~RenderBuffer(){}
00066
00067 }
00068
00069 #else // OpenGL available
00070
00071
00072
00073
00074 #include "Robots/LoBot/ui/LoRenderBuffer.H"
00075 #include "Robots/LoBot/misc/LoExcept.H"
00076
00077
00078 #include "Util/log.H"
00079
00080
00081 #ifdef INVT_HAVE_LIBGLEW
00082 #include <GL/glew.h>
00083 #endif
00084
00085 #define GL_GLEXT_PROTOTYPES
00086 #include <GL/gl.h>
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 #ifdef LOBOT_TRACE_RENDER_BUFFER // use INVT LERROR for trace messages
00105 #define LRB_TRACE LERROR
00106 #else // no tracing ==> LRB_TRACE = nop
00107 #define LRB_TRACE(...)
00108 #endif
00109
00110
00111
00112 namespace lobot {
00113
00114
00115
00116
00117
00118
00119
00120 #ifdef GL_VERSION_4_0
00121
00122
00123
00124 RenderBuffer::RenderBuffer(int W, int H)
00125 : m_width(W), m_height(H),
00126 m_size(W * H * 4), m_cache(new unsigned char[m_size]), m_dirty(true)
00127 {
00128 LRB_TRACE("initializing off-screen rendering using core GL API...") ;
00129
00130 glGenFramebuffers(1, &m_fbo) ;
00131 glBindFramebuffer(GL_FRAMEBUFFER, m_fbo) ;
00132
00133 glGenRenderbuffers(1, &m_rbo) ;
00134 glBindRenderbuffer(GL_RENDERBUFFER, m_rbo) ;
00135 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, m_width, m_height) ;
00136 if (glGetError() != GL_NO_ERROR) {
00137 clean_up() ;
00138 throw misc_error(OPENGL_FBO_INIT_ERROR) ;
00139 }
00140
00141 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
00142 GL_RENDERBUFFER, m_rbo) ;
00143
00144 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
00145 clean_up() ;
00146 throw misc_error(OPENGL_FBO_INIT_ERROR) ;
00147 }
00148
00149 std::fill_n(m_cache, m_size, 0) ;
00150 }
00151
00152
00153 void RenderBuffer::setup()
00154 {
00155 glBindFramebuffer(GL_FRAMEBUFFER, m_fbo) ;
00156 m_dirty = true ;
00157 }
00158
00159
00160 const unsigned char* RenderBuffer::pixels() const
00161 {
00162 if (m_dirty)
00163 {
00164 LRB_TRACE("retrieving off-screen buffer's pixel data...") ;
00165 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo) ;
00166 glReadPixels(0, 0, m_width, m_height,
00167 GL_BGRA, GL_UNSIGNED_BYTE, m_cache) ;
00168 if (glGetError() == GL_NO_ERROR)
00169 m_dirty = false ;
00170 else
00171 std::fill_n(m_cache, m_size, 0) ;
00172 }
00173 else
00174 LRB_TRACE("returning cached off-screen buffer pixel data...") ;
00175 return m_cache ;
00176 }
00177
00178
00179 void RenderBuffer::to_screen()
00180 {
00181 LRB_TRACE("blitting off-screen buffer to back buffer...") ;
00182
00183 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo) ;
00184 glReadBuffer(GL_COLOR_ATTACHMENT0) ;
00185
00186 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0) ;
00187 glDrawBuffer(GL_BACK) ;
00188
00189 glBlitFramebuffer(0, 0, m_width, m_height,
00190 0, 0, m_width, m_height,
00191 GL_COLOR_BUFFER_BIT, GL_NEAREST) ;
00192 }
00193
00194
00195 void RenderBuffer::clean_up()
00196 {
00197 LRB_TRACE("cleaning up off-screen buffer...") ;
00198
00199 glBindFramebuffer (GL_FRAMEBUFFER, 0) ;
00200 glBindRenderbuffer(GL_RENDERBUFFER, 0) ;
00201
00202 glDeleteRenderbuffers(1, &m_rbo) ;
00203 glDeleteFramebuffers (1, &m_fbo) ;
00204
00205 delete[] m_cache ; m_cache = 0 ;
00206 }
00207
00208 RenderBuffer::~RenderBuffer()
00209 {
00210 clean_up() ;
00211 }
00212
00213
00214
00215 #elif defined(GL_EXT_framebuffer_object)
00216
00217
00218 #ifndef INVT_HAVE_LIBGLEW
00219
00220 RenderBuffer::RenderBuffer(int, int)
00221 : m_width(0), m_height(0),
00222 m_size(0), m_cache(0), m_dirty(true),
00223 m_fbo(0), m_rbo(0)
00224 {
00225 throw missing_libs(MISSING_GLEW) ;
00226 }
00227
00228 void RenderBuffer::setup(){}
00229 const unsigned char* RenderBuffer::pixels() const {return 0 ;}
00230 void RenderBuffer::to_screen(){}
00231 void RenderBuffer::clean_up(){}
00232 RenderBuffer::~RenderBuffer(){}
00233
00234 #else // OpenGL extension wrangler library (GLEW) is available
00235
00236
00237 RenderBuffer::RenderBuffer(int W, int H)
00238 : m_width(W), m_height(H),
00239 m_size(W * H * 4), m_cache(new unsigned char[m_size]), m_dirty(true)
00240 {
00241 if (glewInit() != GLEW_OK) {
00242 delete[] m_cache ;
00243 throw misc_error(GLEW_INIT_ERROR) ;
00244 }
00245
00246 if (GLEW_EXT_framebuffer_object)
00247 {
00248 LRB_TRACE("initializing off-screen rendering using GL extension API...");
00249
00250 glGenFramebuffersEXT(1, &m_fbo) ;
00251 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo) ;
00252
00253 glGenRenderbuffersEXT(1, &m_rbo) ;
00254 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_rbo) ;
00255 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8,
00256 m_width, m_height) ;
00257 if (glGetError() != GL_NO_ERROR) {
00258 clean_up() ;
00259 throw misc_error(OPENGL_FBO_INIT_ERROR) ;
00260 }
00261
00262 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
00263 GL_COLOR_ATTACHMENT0_EXT,
00264 GL_RENDERBUFFER_EXT, m_rbo) ;
00265
00266 GLenum fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) ;
00267 if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
00268 clean_up() ;
00269 throw misc_error(OPENGL_FBO_INIT_ERROR) ;
00270 }
00271 }
00272 else
00273 LRB_TRACE("GL driver lacks FBO support ==> no off-screen rendering!") ;
00274 std::fill_n(m_cache, m_size, 0) ;
00275 }
00276
00277
00278 void RenderBuffer::setup()
00279 {
00280 if (GLEW_EXT_framebuffer_object)
00281 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo) ;
00282 m_dirty = true ;
00283 }
00284
00285
00286
00287
00288
00289
00290
00291
00292 const unsigned char* RenderBuffer::pixels() const
00293 {
00294 if (m_dirty)
00295 {
00296 if (GLEW_EXT_framebuffer_object)
00297 {
00298 LRB_TRACE("retrieving off-screen buffer's pixel data...") ;
00299 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo) ;
00300 }
00301 else
00302 {
00303 LRB_TRACE("retrieving back buffer's pixel data...") ;
00304 glReadBuffer(GL_BACK) ;
00305 }
00306 glReadPixels(0, 0, m_width, m_height,
00307 GL_BGRA, GL_UNSIGNED_BYTE, m_cache) ;
00308 if (glGetError() == GL_NO_ERROR)
00309 m_dirty = false ;
00310 else
00311 std::fill_n(m_cache, m_size, 0) ;
00312 }
00313 else
00314 LRB_TRACE("returning cached off-screen buffer pixel data...") ;
00315 return m_cache ;
00316 }
00317
00318
00319
00320
00321
00322 void RenderBuffer::to_screen()
00323 {
00324 #ifdef GL_EXT_framebuffer_blit
00325
00326 if (GLEW_EXT_framebuffer_blit)
00327 {
00328 LRB_TRACE("blitting off-screen buffer to back buffer...") ;
00329
00330 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_fbo) ;
00331 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT) ;
00332
00333 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0) ;
00334 glDrawBuffer(GL_BACK) ;
00335
00336 glBlitFramebufferEXT(0, 0, m_width, m_height,
00337 0, 0, m_width, m_height,
00338 GL_COLOR_BUFFER_BIT, GL_NEAREST) ;
00339 }
00340 else
00341 #else
00342
00343 #endif
00344 if (GLEW_EXT_framebuffer_object)
00345 {
00346 LRB_TRACE("copying pixels from off-screen buffer to back buffer...") ;
00347
00348
00349 pixels() ;
00350
00351
00352 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0) ;
00353 glViewport(0, 0, m_width, m_height) ;
00354
00355
00356
00357
00358
00359 glMatrixMode(GL_PROJECTION) ;
00360 glPushMatrix() ;
00361 glLoadIdentity() ;
00362 glOrtho(0, m_width, 0, m_height, -1, 1) ;
00363
00364 glMatrixMode(GL_MODELVIEW) ;
00365 glPushMatrix() ;
00366 glLoadIdentity() ;
00367 glRasterPos2i(0, 0) ;
00368
00369 glDrawPixels(m_width, m_height, GL_BGRA, GL_UNSIGNED_BYTE, m_cache) ;
00370
00371
00372
00373
00374 glMatrixMode(GL_PROJECTION) ;
00375 glPopMatrix() ;
00376 glMatrixMode(GL_MODELVIEW) ;
00377 glPopMatrix() ;
00378 }
00379 }
00380
00381
00382 void RenderBuffer::clean_up()
00383 {
00384 if (GLEW_EXT_framebuffer_object)
00385 {
00386 LRB_TRACE("cleaning up off-screen buffer related GL resources") ;
00387
00388 glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) ;
00389 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0) ;
00390
00391 glDeleteRenderbuffersEXT(1, &m_rbo) ;
00392 glDeleteFramebuffersEXT (1, &m_fbo) ;
00393 }
00394
00395 delete[] m_cache ; m_cache = 0 ;
00396 }
00397
00398 RenderBuffer::~RenderBuffer()
00399 {
00400 clean_up() ;
00401 }
00402
00403 #endif // #ifndef INVT_HAVE_LIBGLEW
00404
00405
00406
00407 #else // GL does not support framebuffer objects
00408
00409
00410
00411
00412
00413 RenderBuffer::RenderBuffer(int W, int H)
00414 : m_width(W), m_height(H),
00415 m_size(W * H * 4), m_cache(new unsigned char[m_size]), m_dirty(true),
00416 m_fbo(0), m_rbo(0)
00417 {
00418 LRB_TRACE("no compile or run-time off-screen rendering support in GL") ;
00419 std::fill_n(m_cache, m_size, 0) ;
00420 }
00421
00422
00423 void RenderBuffer::setup(){}
00424
00425
00426
00427
00428
00429
00430
00431
00432 const unsigned char* RenderBuffer::pixels() const
00433 {
00434 if (m_dirty)
00435 {
00436 LRB_TRACE("retrieving back buffer's pixel data...") ;
00437 glReadBuffer(GL_BACK) ;
00438 glReadPixels(0, 0, m_width, m_height,
00439 GL_BGRA, GL_UNSIGNED_BYTE, m_cache) ;
00440 if (glGetError() == GL_NO_ERROR)
00441 m_dirty = false ;
00442 else
00443 std::fill_n(m_cache, m_size, 0) ;
00444 }
00445 else
00446 LRB_TRACE("returning cached off-screen buffer pixel data...") ;
00447 return m_cache ;
00448 }
00449
00450
00451
00452 void RenderBuffer::to_screen(){}
00453
00454
00455 void RenderBuffer::clean_up(){}
00456
00457 RenderBuffer::~RenderBuffer()
00458 {
00459 delete[] m_cache ;
00460 }
00461
00462 #endif // defined(GL_EXT_framebuffer_object)
00463
00464
00465
00466 }
00467
00468 #endif // #ifndef INVT_HAVE_LIBGL
00469
00470
00471
00472
00473