LoRenderBuffer.C

Go to the documentation of this file.
00001 /**
00002    \file Robots/LoBot/ui/LoRenderBuffer.C
00003 
00004    \brief This file defines the non-inline member functions of the
00005    lobot::RenderBuffer class, which is used to implement an off-screen
00006    rendering buffer via OpenGL's framebuffer object API.
00007 */
00008 
00009 // //////////////////////////////////////////////////////////////////// //
00010 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00011 // by the University of Southern California (USC) and the iLab at USC.  //
00012 // See http://iLab.usc.edu for information about this project.          //
00013 // //////////////////////////////////////////////////////////////////// //
00014 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00015 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00016 // in Visual Environments, and Applications'' by Christof Koch and      //
00017 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00018 // pending; application number 09/912,225 filed July 23, 2001; see      //
00019 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00020 // //////////////////////////////////////////////////////////////////// //
00021 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00022 //                                                                      //
00023 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00024 // redistribute it and/or modify it under the terms of the GNU General  //
00025 // Public License as published by the Free Software Foundation; either  //
00026 // version 2 of the License, or (at your option) any later version.     //
00027 //                                                                      //
00028 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00029 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00030 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00031 // PURPOSE.  See the GNU General Public License for more details.       //
00032 //                                                                      //
00033 // You should have received a copy of the GNU General Public License    //
00034 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00035 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00036 // Boston, MA 02111-1307 USA.                                           //
00037 // //////////////////////////////////////////////////////////////////// //
00038 //
00039 // Primary maintainer for this file: mviswana usc edu
00040 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/ui/LoRenderBuffer.C $
00041 // $Id: LoRenderBuffer.C 13838 2010-08-27 20:42:20Z mviswana $
00042 //
00043 
00044 //-------------------------- OPENGL MISSING -----------------------------
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 } // end of namespace encapsulating above empty definition
00068 
00069 #else // OpenGL available
00070 
00071 //------------------------------ HEADERS --------------------------------
00072 
00073 // lobot headers
00074 #include "Robots/LoBot/ui/LoRenderBuffer.H"
00075 #include "Robots/LoBot/misc/LoExcept.H"
00076 
00077 // INVT headers
00078 #include "Util/log.H"
00079 
00080 // OpenGL headers
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 //------------------------------ MACROS ---------------------------------
00089 
00090 // Since off-screen rendering support depends heavily on OpenGL versions
00091 // and extension availability, it is useful to be able to see some
00092 // diagnostic messages about how this module goes about implementing its
00093 // off-screen rendering API. This symbol can be used to turn this
00094 // diagnostic tracing on. In normal use, it would be best to keep the
00095 // following line commented.
00096 //#define LOBOT_TRACE_RENDER_BUFFER
00097 
00098 // We simply use INVT's LERROR to implement the tracing functionality
00099 // alluded to above. However, to be able to turn tracing on/off without
00100 // having to manually comment each and every LERROR or to wrap each
00101 // LERROR inside of an #ifdef LOBOT_TRACE_RENDER_BUFFER block, we use the
00102 // following macro, viz., LRB_TRACE (LRB = lobot render buffer), and
00103 // define it appropriately depending on whether tracing is on or off.
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 //----------------------------- NAMESPACE -------------------------------
00111 
00112 namespace lobot {
00113 
00114 //------------------ FRAMEBUFFER OBJECTS IN GL CORE ---------------------
00115 
00116 // DEVNOTE: THIS CODE IS SUSPECT!
00117 //
00118 // It was never actually built and run on a machine that had the FBO API
00119 // in the GL core.
00120 #ifdef GL_VERSION_4_0
00121 //#warning "framebuffer objects are part of GL core"
00122 
00123 // Initialize off-screen rendering buffer of specified size
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 // Setup off-screen rendering
00153 void RenderBuffer::setup()
00154 {
00155    glBindFramebuffer(GL_FRAMEBUFFER, m_fbo) ;
00156    m_dirty = true ;
00157 }
00158 
00159 // Retrieve off-screen buffer's pixel data
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 // Copy contents of off-screen buffer to the back buffer
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 // Clean-up
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 //---------------- FRAMEBUFFER OBJECTS IN GL EXTENSION ------------------
00214 
00215 #elif defined(GL_EXT_framebuffer_object)
00216 //#warning "framebuffer objects are a GL extension"
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 // Initialize off-screen rendering buffer of specified size
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 // Setup off-screen rendering
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 // Retrieve off-screen buffer's pixel data
00286 //
00287 // NOTE: If GL doesn't support framebuffer objects, we will simply read
00288 // the back buffer, which can cause bogus screen captures, e.g., window
00289 // obscured by another. But, unfortunately, that's the best we can do
00290 // with GLUT. If we were using GLX instead, we could have tested for the
00291 // pbuffer extension and used that...
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 // Copy contents of off-screen buffer to the back buffer
00319 //
00320 // DEVNOTE: The blit code is suspect! It was never run on a host where
00321 // the GL driver supported blitting.
00322 void RenderBuffer::to_screen()
00323 {
00324 #ifdef GL_EXT_framebuffer_blit
00325 //#warning "FBO extension supports blitting"
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 //#warning "FBO extension does not support blitting"
00343 #endif
00344    if (GLEW_EXT_framebuffer_object)
00345    {
00346       LRB_TRACE("copying pixels from off-screen buffer to back buffer...") ;
00347 
00348       // Read pixels from off-screen buffer
00349       pixels() ; // stuffs pixel data into m_cache
00350 
00351       // Copy above pixels to GL back (on-screen) buffer
00352       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0) ;
00353       glViewport(0, 0, m_width, m_height) ;
00354 
00355       // Since pixel copying will go through the usual graphics pipeline,
00356       // we should reset the projection and modelview matrices so that
00357       // the matrices used for rendering to the off-screen buffer don't
00358       // mess up the scene that finally gets shown on-screen.
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       // Restore matrices so that clients can remain blissfully unaware
00372       // of the fact that they are actually rendering to an off-screen
00373       // buffer...
00374       glMatrixMode(GL_PROJECTION) ;
00375       glPopMatrix() ;
00376       glMatrixMode(GL_MODELVIEW) ;
00377       glPopMatrix() ;
00378    }
00379 }
00380 
00381 // Clean-up
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 //----------------- FRAMEBUFFER OBJECTS NOT AVAILABLE -------------------
00406 
00407 #else // GL does not support framebuffer objects
00408 //#warning "GL does not support framebuffer objects"
00409 
00410 // Initialization: since we don't have off-screen rendering, all
00411 // "off-screen" rendering is in fact simply redirected to the GL back
00412 // (on-screen) buffer.
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 // Nothing to setup because all rendering is on-screen
00423 void RenderBuffer::setup(){}
00424 
00425 // Retrieve pixel data from back buffer
00426 //
00427 // NOTE: This can be problematic due to pixel ownership tests. For
00428 // example, if the Robolocust window is partially obscured by another,
00429 // the screen capture can be corrupt. But without framebuffer objects, we
00430 // have little recourse short of switching from GLUT to GLX and trying
00431 // our luck with something like the pbuffer extension...
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 // Nothing to do for copying off-screen buffer to on-screen buffer
00451 // because all rendering is already taking place in on-screen buffer.
00452 void RenderBuffer::to_screen(){}
00453 
00454 // Clean-up
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 } // end of namespace encapsulating this file's definitions
00467 
00468 #endif // #ifndef INVT_HAVE_LIBGL
00469 
00470 /* So things look consistent in everyone's emacs... */
00471 /* Local Variables: */
00472 /* indent-tabs-mode: nil */
00473 /* End: */
Generated on Sun May 8 08:41:31 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3