JWS C++ Library
C++ language utility library
|
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