JWS C++ Library
C++ language utility library
offscreen.cpp
Go to the documentation of this file.
00001 /*
00002  * This work is licensed under a Creative Commons 
00003  * Attribution-Noncommercial-Share Alike 3.0 United States License.
00004  * 
00005  *    http://creativecommons.org/licenses/by-nc-sa/3.0/us/
00006  * 
00007  * You are free:
00008  * 
00009  *    to Share - to copy, distribute, display, and perform the work
00010  *    to Remix - to make derivative works
00011  * 
00012  * Under the following conditions:
00013  * 
00014  *    Attribution. You must attribute the work in the manner specified by the
00015  *    author or licensor (but not in any way that suggests that they endorse you
00016  *    or your use of the work).
00017  * 
00018  *    Noncommercial. You may not use this work for commercial purposes.
00019  * 
00020  *    Share Alike. If you alter, transform, or build upon this work, you may
00021  *    distribute the resulting work only under the same or similar license to
00022  *    this one.
00023  * 
00024  * For any reuse or distribution, you must make clear to others the license
00025  * terms of this work. The best way to do this is by including this header.
00026  * 
00027  * Any of the above conditions can be waived if you get permission from the
00028  * copyright holder.
00029  * 
00030  * Apart from the remix rights granted under this license, nothing in this
00031  * license impairs or restricts the author's moral rights.
00032  */
00033 
00034 
00049 #include <jwsc++/config.h>
00050 
00051 #include <cstdlib>
00052 #include <cassert>
00053 #include <cstring>
00054 #include <sstream>
00055 
00056 #if defined JWSCXX_HAVE_X11 && defined JWSCXX_HAVE_GLX
00057 #include <X11/Xlib.h>
00058 #include <GL/gl.h>
00059 #include <GL/glx.h>
00060 #elif defined JWSCXX_HAVE_OPENGL_FRAMEWORK
00061 #include <OpenGL/OpenGL.h>
00062 #include <OpenGL/gl.h>
00063 #endif
00064 
00065 #include "jwsc++/graphics/offscreen.h"
00066 
00067 #ifdef JWSCXX_HAVE_DMALLOC
00068 #include <dmalloc.h>
00069 #endif
00070 
00071 
00072 using namespace jwscxx::base;
00073 using namespace jwscxx::graphics;
00074 
00075 
00076 #if defined JWSCXX_HAVE_X11 && defined JWSCXX_HAVE_GLX
00077 /* -----------------------  GLX_offscreen_buffer  --------------------------- */
00078 
00079 void GLX_offscreen_buffer::activate() throw (jwscxx::base::Exception)
00080 {
00081     if (!active)
00082     {
00083         if (!(active = glXMakeCurrent(display, drawable, context)))
00084         {
00085             throw jwscxx::base::Exception(
00086                     "Could not make drawable context current");
00087         }
00088     }
00089 }
00090 
00091 void GLX_offscreen_buffer::deactivate() throw (jwscxx::base::Exception)
00092 {
00093     if (active)
00094     {
00095         if ((active = !glXMakeCurrent(display, old_drawable, old_context)))
00096         {
00097             throw jwscxx::base::Exception(
00098                     "Could not make old drawable context current");
00099         }
00100     }
00101 }
00102 
00103 void GLX_offscreen_buffer::reactivate() throw (jwscxx::base::Exception)
00104 {
00105     if (!active)
00106     {
00107         throw jwscxx::base::Exception("No active context to reactivate");
00108     }
00109     if (glXMakeCurrent(display, drawable, context))
00110     {
00111         throw jwscxx::base::Exception("Could not make context current");
00112     }
00113 }
00114 
00115 void GLX_offscreen_buffer::open_display(const char* disp_name)
00116     throw(jwscxx::base::Result_error)
00117 {
00118     display = glXGetCurrentDisplay();
00119 
00120     if (!display)
00121     {
00122         display = XOpenDisplay(disp_name);
00123 
00124         if (!display && !disp_name)
00125         {
00126             std::ostringstream ost;
00127             ost << "Could not open X display '" << getenv("DISPLAY") << '\'';
00128             throw jwscxx::base::Result_error(ost.str());
00129         }
00130         else if (!display)
00131         {
00132             std::ostringstream ost;
00133             ost << "Could not open X display '" << disp_name << '\'';
00134             throw jwscxx::base::Result_error(ost.str());
00135         }
00136 
00137         display_open = true;
00138     }
00139 }
00140 
00141 void GLX_offscreen_buffer::save_old_context()
00142 {
00143     // Grab the current drawable and context there might be none, in which case
00144     // these will be 0.
00145     old_drawable = glXGetCurrentDrawable();
00146     old_context = glXGetCurrentContext();
00147 }
00148 
00149 /* ---------------------------------------------------------------------------*/
00150 
00151 
00152 
00153 
00154 
00155 
00156 
00157 /* -------------------------  GLX_offscreen_pixmap  --------------------------*/
00158 
00159 GLX_offscreen_pixmap::GLX_offscreen_pixmap
00160 (
00161     int  width, 
00162     int  height, 
00163     int* attrs
00164 )
00165 throw (jwscxx::base::Exception) : GLX_offscreen_buffer(width, height)
00166 {
00167     open_display();
00168     save_old_context();
00169     create_drawable_and_context(attrs);
00170 }
00171 
00172 GLX_offscreen_pixmap::~GLX_offscreen_pixmap()
00173 {
00174     if (active)
00175     {
00176         deactivate();
00177     }
00178 
00179     glXDestroyContext(display, context);
00180     destroy_drawable();
00181 
00182     if (display_open)
00183     {
00184         XCloseDisplay(display);
00185     }
00186 }
00187 
00188 void GLX_offscreen_pixmap::create_drawable_and_context(int* attrs)
00189     throw (jwscxx::base::Result_error)
00190 {
00191     static int default_attrs[] = { GLX_RGBA,
00192                                    GLX_RED_SIZE,     8,
00193                                    GLX_GREEN_SIZE,   8,
00194                                    GLX_BLUE_SIZE,    8,
00195                                    GLX_ALPHA_SIZE,   8,
00196                                    GLX_DEPTH_SIZE,   4,
00197                                    GLX_STENCIL_SIZE, 4,
00198                                    None };
00199 
00200     if (!attrs)
00201     {
00202         attrs = default_attrs;
00203     }
00204 
00205     XVisualInfo *visual = glXChooseVisual(display, 
00206             DefaultScreen(display), attrs);
00207     if (!visual)
00208     {
00209         throw jwscxx::base::Result_error("Could not get X visual");
00210     }
00211 
00212     pixmap = XCreatePixmap(display, DefaultRootWindow(display),
00213                 width, height, visual->depth);
00214     if (!pixmap)
00215     {
00216         throw jwscxx::base::Result_error("Could not create X11 pixmap");
00217     }
00218 
00219     drawable = glXCreateGLXPixmap(display, visual, pixmap);
00220     if (!drawable)
00221     {
00222         throw jwscxx::base::Result_error("Could not create GLX pixmap");
00223     }
00224 
00225     context = glXCreateContext(display, visual, 0, GL_FALSE);
00226     if (!context)
00227     {
00228         throw jwscxx::base::Result_error("Could not create GLX context");
00229     }
00230 }
00231 
00232 void GLX_offscreen_pixmap::destroy_drawable()
00233 {
00234     glXDestroyPixmap(display, drawable);
00235     XFreePixmap(display, pixmap);
00236 }
00237 
00238 /* ---------------------------------------------------------------------------*/
00239 
00240 
00241 
00242 
00243 
00244 
00245 /* -------------------------  GLX_offscreen_pbuffer  -------------------------*/
00246 
00247 GLX_offscreen_pbuffer::GLX_offscreen_pbuffer
00248 (
00249     int  width, 
00250     int  height, 
00251     int* attrs
00252 )
00253 throw (jwscxx::base::Exception)
00254     : GLX_offscreen_buffer(width, height)
00255 {
00256     open_display();
00257 
00258     if (!has_pbuffer_extension())
00259     {
00260         throw jwscxx::base::Result_error("PBuffers not supported");
00261     }
00262 
00263     save_old_context();
00264     create_drawable_and_context(attrs);
00265 }
00266 
00267 GLX_offscreen_pbuffer::~GLX_offscreen_pbuffer()
00268 {
00269     if (active)
00270     {
00271         deactivate();
00272     }
00273 
00274     glXDestroyContext(display, context);
00275     destroy_drawable();
00276 
00277     if (display_open)
00278     {
00279         XCloseDisplay(display);
00280     }
00281 }
00282     
00283 void GLX_offscreen_pbuffer::create_drawable_and_context(int* attrs)
00284     throw(jwscxx::base::Exception)
00285 {
00286     static int default_attrs[] = { GLX_RED_SIZE,     8,
00287                                    GLX_GREEN_SIZE,   8,
00288                                    GLX_BLUE_SIZE,    8,
00289                                    GLX_ALPHA_SIZE,   8,
00290                                    GLX_DEPTH_SIZE,   4,
00291                                    GLX_STENCIL_SIZE, 1,
00292                                    None };
00293 
00294     int pbuf_attrs[] = { GLX_PBUFFER_WIDTH, width, 
00295                          GLX_PBUFFER_HEIGHT, height,
00296                          GLX_PRESERVED_CONTENTS, GL_TRUE,
00297                          None };
00298 
00299     if (!attrs)
00300     {
00301         attrs = default_attrs;
00302     }
00303 
00304     int nlist;
00305     GLXFBConfig *fbconfig = glXChooseFBConfig(display, DefaultScreen(display),
00306                 attrs, &nlist);
00307     if (!fbconfig)
00308     {
00309         throw jwscxx::base::Result_error("Could not create pbuffer");
00310     }
00311 
00312     for (int i = 0; i < nlist; i++)
00313     {
00314         drawable = glXCreatePbuffer(display, fbconfig[i], pbuf_attrs);
00315 
00316         if (drawable)
00317         {
00318             context = glXCreateNewContext(display, fbconfig[i], GLX_RGBA_TYPE,
00319                     0, GL_TRUE);
00320 
00321             XFree(fbconfig);
00322 
00323             if(!context)
00324             {
00325                 throw jwscxx::base::Result_error("Could not create context");
00326             }
00327 
00328             return;
00329         }
00330     }
00331 
00332     XFree(fbconfig);
00333 
00334     throw jwscxx::base::Result_error("Could not find valid framebuffer config");
00335 }
00336 
00337 void GLX_offscreen_pbuffer::destroy_drawable()
00338 {
00339     glXDestroyPbuffer(display, drawable);
00340 }
00341 
00342 bool GLX_offscreen_pbuffer::has_pbuffer_extension() const
00343 {
00344     bool has_pbuffer = false;
00345 
00346     const char* ext = glXQueryServerString(display, 0, GLX_EXTENSIONS);
00347     char* ext_buf = (char*)malloc(strlen(ext)*sizeof(char));
00348     char* ext_ptr = ext_buf;
00349     strcpy(ext_ptr, ext);
00350     ext_ptr = strtok(ext_ptr, " ");
00351     do
00352     {
00353         if (strcmp(ext_ptr, "GLX_SGIX_pbuffer") == 0)
00354         {
00355             has_pbuffer = true;
00356         }
00357     } while ((ext_ptr = strtok(0, " ")));
00358     free(ext_buf);
00359 
00360     return has_pbuffer;
00361 }
00362 
00363 /* ---------------------------------------------------------------------------*/
00364 
00365 
00366 
00367 
00368 
00369 
00370 
00371 #elif defined JWSCXX_HAVE_OPENGL_FRAMEWORK
00372 /* -------------------------  CGL_offscreen_pbuffer  -------------------------*/
00373 
00377 CGL_offscreen_pbuffer::CGL_offscreen_pbuffer
00378 (
00379     GLsizei width, 
00380     GLsizei height, 
00381     GLenum  format,
00382     const CGLPixelFormatAttribute* attrs
00383 )
00384 throw (jwscxx::base::Exception) : Offscreen_buffer(width, height)
00385 {
00386     save_old_context();
00387     create_pbuffer_and_context(format, attrs);
00388 }
00389 
00390 CGL_offscreen_pbuffer::~CGL_offscreen_pbuffer()
00391 {
00392     if (active)
00393     {
00394         deactivate();
00395     }
00396 
00397     CGLDestroyContext(context);
00398     CGLDestroyPBuffer(pbuffer);
00399 }
00400     
00401 void CGL_offscreen_pbuffer::activate() throw (jwscxx::base::Exception)
00402 {
00403     if (!active)
00404     {
00405         active = !CGLSetCurrentContext(context);
00406         if (!active)
00407         {
00408             throw jwscxx::base::Exception("Could not make context current");
00409         }
00410     }
00411 }
00412 
00413 void CGL_offscreen_pbuffer::deactivate() throw (jwscxx::base::Exception)
00414 {
00415     if (active)
00416     {
00417         active = CGLSetCurrentContext(old_context);
00418         if (active)
00419         {
00420             throw jwscxx::base::Exception(
00421                     "Could not make old context current");
00422         }
00423     }
00424 }
00425 
00426 
00427 void CGL_offscreen_pbuffer::reactivate() throw (jwscxx::base::Exception)
00428 {
00429     if (!active)
00430     {
00431         throw jwscxx::base::Exception("No active context to reactivate");
00432     }
00433     if (CGLSetCurrentContext(context))
00434     {
00435         throw jwscxx::base::Exception("Could not make context current");
00436     }
00437 }
00438 
00439 void CGL_offscreen_pbuffer::create_pbuffer_and_context
00440 (
00441     GLenum format,
00442     const CGLPixelFormatAttribute* attrs
00443 )
00444 throw(jwscxx::base::Exception)
00445 {
00446     static const CGLPixelFormatAttribute default_attrs[] = 
00447                                       { kCGLPFAColorSize,   
00448                                         (CGLPixelFormatAttribute)24,
00449                                         kCGLPFAAlphaSize,   
00450                                         (CGLPixelFormatAttribute)8,
00451                                         kCGLPFADepthSize,   
00452                                         (CGLPixelFormatAttribute)32,
00453                                         kCGLPFAAccelerated,
00454                                         kCGLPFAPBuffer,
00455                                         (CGLPixelFormatAttribute)0 };
00456 
00457     if (!attrs)
00458     {
00459         attrs = default_attrs;
00460     }
00461 
00462     CGLPixelFormatObj pxlfmt;
00463     GLint nlist;
00464     if (CGLChoosePixelFormat(attrs, &pxlfmt, &nlist))
00465     {
00466         throw jwscxx::base::Result_error("Could not choose pixel format");
00467     }
00468 
00469     for (int i = 0; i < nlist; i++)
00470     {
00471         CGLError err = CGLCreateContext(pxlfmt, 0, &context);
00472 
00473         if (!err)
00474         {
00475             break;
00476         }
00477         else if (err != kCGLBadPixelFormat || 
00478                 ((nlist - i) == 1 && err == kCGLBadPixelFormat))
00479         {
00480             CGLDestroyPixelFormat(pxlfmt);
00481             throw jwscxx::base::Result_error("Could not create context");
00482         }
00483     }
00484 
00485     CGLDestroyPixelFormat(pxlfmt);
00486 
00487     GLint screen;
00488     if (CGLGetVirtualScreen(context, &screen))
00489     {
00490         throw jwscxx::base::Result_error("Could not get virtual screen");
00491     }
00492 
00493     if (CGLCreatePBuffer(width, height, GL_TEXTURE_RECTANGLE_EXT, format, 0, 
00494                 &pbuffer))
00495     {
00496         throw jwscxx::base::Result_error("Could not create pbuffer");
00497     }
00498 
00499     if (CGLSetPBuffer(context, pbuffer, 0, 0, screen))
00500     {
00501         throw jwscxx::base::Result_error("Could not set pbuffer");
00502     }
00503 }
00504 
00505 void CGL_offscreen_pbuffer::save_old_context()
00506 {
00507     old_context = CGLGetCurrentContext();
00508 }
00509 
00510 /* ---------------------------------------------------------------------------*/
00511 #endif
00512 
00513 
00514 
00515 
00516 
00517 #if defined JWSCXX_HAVE_OSMESA32
00518 /* ----------------------  OSMesa32_offscreen_buffer  ------------------------*/
00519 
00524 OSMesa32_offscreen_buffer::OSMesa32_offscreen_buffer
00525 (
00526     GLsizei width, 
00527     GLsizei height, 
00528     GLenum  format,
00529     GLint   depth_bits,
00530     GLint   stencil_bits,
00531     GLint   accum_bits
00532 )
00533 throw (jwscxx::base::Exception) : Offscreen_buffer(width, height)
00534 {
00535     create_buffer_and_context(format, depth_bits, stencil_bits, accum_bits);
00536 }
00537 
00538 OSMesa32_offscreen_buffer::~OSMesa32_offscreen_buffer()
00539 {
00540     if (active)
00541     {
00542         deactivate();
00543     }
00544 
00545     OSMesaDestroyContext(context);
00546     free(buffer);
00547 }
00548     
00549 void OSMesa32_offscreen_buffer::activate() throw (jwscxx::base::Exception)
00550 {
00551     if (!active)
00552     {
00553         if (!(active = OSMesaMakeCurrent(context, buffer, GL_UNSIGNED_BYTE, 
00554                         width, height)))
00555         {
00556             throw jwscxx::base::Exception("Could not make context current");
00557         }
00558     }
00559 }
00560 
00561 void OSMesa32_offscreen_buffer::deactivate() throw (jwscxx::base::Exception)
00562 {
00563     if (active)
00564     {
00565         active = false;
00566     }
00567 }
00568 
00569 void OSMesa32_offscreen_buffer::reactivate() throw (jwscxx::base::Exception)
00570 {
00571     if (!active)
00572     {
00573         throw jwscxx::base::Exception("No active context to reactivate");
00574     }
00575     // Nothing to do.
00576 }
00577 
00578 void OSMesa32_offscreen_buffer::create_buffer_and_context
00579 (
00580     GLenum format,
00581     GLint  depth_bits,
00582     GLint  stencil_bits,
00583     GLint  accum_bits
00584 )
00585 throw(jwscxx::base::Exception)
00586 {
00587     context = OSMesaCreateContextExt(format, depth_bits, stencil_bits, 
00588             accum_bits, 0);
00589     if (!context)
00590     {
00591         throw jwscxx::base::Result_error("Could not create context");
00592     }
00593 
00594     buffer = malloc(width * height * 4 * sizeof(GLbyte));
00595     if (!buffer)
00596     {
00597         throw jwscxx::base::Result_error("Could not create buffer");
00598     }
00599 }
00600 
00601 /* ---------------------------------------------------------------------------*/
00602 #endif