00001 /* 00002 ----------------------------------------------------------------------------- 00003 This source file is part of OGRE 00004 (Object-oriented Graphics Rendering Engine) 00005 For the latest info, see http://www.ogre3d.org/ 00006 00007 Copyright ? 2000-2004 The OGRE Team 00008 Also see acknowledgements in Readme.html 00009 00010 This program is free software; you can redistribute it and/or modify it under 00011 the terms of the GNU Lesser General Public License as published by the Free Software 00012 Foundation; either version 2 of the License, or (at your option) any later 00013 version. 00014 00015 This program is distributed in the hope that it will be useful, but WITHOUT 00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 00018 00019 You should have received a copy of the GNU Lesser General Public License along with 00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple 00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to 00022 http://www.gnu.org/copyleft/lesser.txt. 00023 ----------------------------------------------------------------------------- 00024 */ 00025 00026 #include "OgreGLXWindow.h" 00027 #include "OgreRoot.h" 00028 #include "OgreRenderSystem.h" 00029 #include "OgreImageCodec.h" 00030 #include "OgreException.h" 00031 #include "OgreLogManager.h" 00032 #include "OgreStringConverter.h" 00033 00034 #include <iostream> 00035 #include <algorithm> 00036 #include <sys/time.h> 00037 #include <climits> 00038 00039 #include <X11/Xlib.h> 00040 #include <X11/keysym.h> 00041 00042 #ifndef NO_XRANDR 00043 #include <X11/extensions/Xrandr.h> 00044 #endif 00045 00046 #include <GL/gl.h> 00047 #include <GL/glu.h> 00048 #include <GL/glx.h> 00049 00050 00051 namespace Ogre { 00052 00053 GLXWindow::GLXWindow(Display *display) : 00054 mDisplay(display), 00055 mWindow(0), 00056 mGlxContext(0), 00057 mActive(false), mClosed(false),mFullScreen(false), mOldMode(-1) {} 00058 00059 GLXWindow::~GLXWindow() { 00060 if(mGlxContext) 00061 glXDestroyContext(mDisplay, mGlxContext); 00062 if(mWindow) 00063 XDestroyWindow(mDisplay, mWindow); 00064 #ifndef NO_XRANDR 00065 00066 if(mFullScreen) { 00067 // Restore original video mode. 00068 Window rootWindow = DefaultRootWindow(mDisplay); 00069 XRRScreenConfiguration *config; 00070 00071 // Get current screen info 00072 config = XRRGetScreenInfo(mDisplay, rootWindow); 00073 if(config) { 00074 Rotation current_rotation; 00075 XRRConfigCurrentConfiguration (config, ¤t_rotation); 00076 //std::cerr << "Restore mode " << mOldMode << std::endl; 00077 LogManager::getSingleton().logMessage("GLXWindow::~GLXWindow -- Leaving full screen mode"); 00078 XRRSetScreenConfig(mDisplay, config, rootWindow, mOldMode, current_rotation, CurrentTime); 00079 XRRFreeScreenConfigInfo(config); 00080 } else { 00081 LogManager::getSingleton().logMessage("GLXWindow::~GLXWindow -- Could not switch from full screen mode: XRRGetScreenInfo failed"); 00082 } 00083 } 00084 #endif 00085 } 00086 00087 namespace { 00088 00100 bool LoadIcon(Display *mDisplay, Window rootWindow, const std::string &name, Pixmap *pix, Pixmap *mask) { 00101 Image img; 00102 int mWidth, mHeight; 00103 char *data, *bitmap; 00104 try { 00105 // Try to load image 00106 img.load(name); 00107 mWidth = img.getWidth(); 00108 mHeight = img.getHeight(); 00109 if(img.getFormat() != PF_A8R8G8B8) 00110 // Image format must be RGBA 00111 return 0; 00112 } catch(Exception &e) { 00113 // Could not find image; never mind 00114 return false; 00115 } 00116 00117 // Allocate space for image data 00118 data = (char*)malloc(mWidth * mHeight * 4); // Must be allocated with malloc 00119 // Allocate space for transparency bitmap 00120 int wbits = (mWidth+7)/8; 00121 bitmap = (char*)malloc(wbits * mHeight); 00122 00123 // Convert and copy image 00124 const char *imgdata = (const char*)img.getData(); 00125 int sptr = 0, dptr = 0; 00126 for(int y=0; y<mHeight; y++) { 00127 for(int x=0; x<mWidth; x++) { 00128 data[dptr + 0] = 0; 00129 data[dptr + 1] = imgdata[sptr + 0]; 00130 data[dptr + 2] = imgdata[sptr + 1]; 00131 data[dptr + 3] = imgdata[sptr + 2]; 00132 // Alpha threshold 00133 if(((unsigned char)imgdata[sptr + 3])<128) { 00134 bitmap[y*wbits+(x>>3)] &= ~(1<<(x&7)); 00135 } else { 00136 bitmap[y*wbits+(x>>3)] |= 1<<(x&7); 00137 } 00138 sptr += 4; 00139 dptr += 4; 00140 } 00141 } 00142 00143 /* put my pixmap data into the client side X image data structure */ 00144 XImage *image = XCreateImage (mDisplay, NULL, 24, ZPixmap, 0, 00145 data, 00146 mWidth, mHeight, 8, 00147 mWidth*4); 00148 image->byte_order = MSBFirst; // 0RGB format 00149 00150 /* tell server to start managing my pixmap */ 00151 Pixmap retval = XCreatePixmap(mDisplay, rootWindow, mWidth, 00152 mHeight, 24); 00153 00154 /* copy from client to server */ 00155 GC context = XCreateGC (mDisplay, rootWindow, 0, NULL); 00156 XPutImage(mDisplay, retval, context, image, 0, 0, 0, 0, 00157 mWidth, mHeight); 00158 00159 /* free up the client side pixmap data area */ 00160 XDestroyImage(image); // also cleans data 00161 XFreeGC(mDisplay, context); 00162 00163 *pix = retval; 00164 *mask = XCreateBitmapFromData(mDisplay, rootWindow, bitmap, mWidth, mHeight); 00165 free(bitmap); 00166 return true; 00167 } 00168 00169 struct visual_attribs 00170 { 00171 /* X visual attribs */ 00172 int id; 00173 int klass; 00174 int depth; 00175 int redMask, greenMask, blueMask; 00176 int colormapSize; 00177 int bitsPerRGB; 00178 00179 /* GL visual attribs */ 00180 int supportsGL; 00181 int transparentType; 00182 int transparentRedValue; 00183 int transparentGreenValue; 00184 int transparentBlueValue; 00185 int transparentAlphaValue; 00186 int transparentIndexValue; 00187 int bufferSize; 00188 int level; 00189 int rgba; 00190 int doubleBuffer; 00191 int stereo; 00192 int auxBuffers; 00193 int redSize, greenSize, blueSize, alphaSize; 00194 int depthSize; 00195 int stencilSize; 00196 int accumRedSize, accumGreenSize, accumBlueSize, accumAlphaSize; 00197 int numSamples, numMultisample; 00198 int visualCaveat; 00199 }; 00200 00201 00202 static void 00203 get_visual_attribs(Display *dpy, XVisualInfo *vInfo, 00204 struct visual_attribs *attribs) { 00205 const char *ext = glXQueryExtensionsString(dpy, vInfo->screen); 00206 00207 memset(attribs, 0, sizeof(struct visual_attribs)); 00208 00209 attribs->id = vInfo->visualid; 00210 #if defined(__cplusplus) || defined(c_plusplus) 00211 00212 attribs->klass = vInfo->c_class; 00213 #else 00214 00215 attribs->klass = vInfo->class; 00216 #endif 00217 00218 attribs->depth = vInfo->depth; 00219 attribs->redMask = vInfo->red_mask; 00220 attribs->greenMask = vInfo->green_mask; 00221 attribs->blueMask = vInfo->blue_mask; 00222 attribs->colormapSize = vInfo->colormap_size; 00223 attribs->bitsPerRGB = vInfo->bits_per_rgb; 00224 00225 if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0) 00226 return; 00227 glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize); 00228 glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level); 00229 glXGetConfig(dpy, vInfo, GLX_RGBA, &attribs->rgba); 00230 glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer); 00231 glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo); 00232 glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers); 00233 glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize); 00234 glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize); 00235 glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize); 00236 glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize); 00237 glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize); 00238 glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize); 00239 glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize); 00240 glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize); 00241 glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize); 00242 glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize); 00243 00244 /* get transparent pixel stuff */ 00245 glXGetConfig(dpy, vInfo,GLX_TRANSPARENT_TYPE, &attribs->transparentType); 00246 if (attribs->transparentType == GLX_TRANSPARENT_RGB) { 00247 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue); 00248 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue); 00249 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue); 00250 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue); 00251 } else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) { 00252 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue); 00253 } 00254 00255 /* multisample attribs */ 00256 #ifdef GLX_ARB_multisample 00257 if (ext && strstr("GLX_ARB_multisample", ext) == 0) { 00258 glXGetConfig(dpy, vInfo, GLX_SAMPLE_BUFFERS_ARB, &attribs->numMultisample); 00259 glXGetConfig(dpy, vInfo, GLX_SAMPLES_ARB, &attribs->numSamples); 00260 } 00261 #endif 00262 else { 00263 attribs->numSamples = 0; 00264 attribs->numMultisample = 0; 00265 } 00266 00267 #if defined(GLX_EXT_visual_rating) 00268 if (ext && strstr(ext, "GLX_EXT_visual_rating")) { 00269 glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat); 00270 } else { 00271 attribs->visualCaveat = GLX_NONE_EXT; 00272 } 00273 #else 00274 attribs->visualCaveat = 0; 00275 #endif 00276 } 00277 00278 /* 00279 * Examine all visuals to find the so-called best one. 00280 * We prefer deepest RGBA buffer with depth, stencil and accum 00281 * that has no caveats. 00282 * @author Brian Paul (from the glxinfo source) 00283 */ 00284 int find_best_visual(Display *dpy, int scrnum) { 00285 XVisualInfo theTemplate; 00286 XVisualInfo *visuals; 00287 int numVisuals; 00288 long mask; 00289 int i; 00290 struct visual_attribs bestVis; 00291 00292 /* get list of all visuals on this screen */ 00293 theTemplate.screen = scrnum; 00294 mask = VisualScreenMask; 00295 visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals); 00296 if(numVisuals == 0 || visuals == 0) { 00297 /* something went wrong */ 00298 if(visuals) 00299 XFree(visuals); 00300 return -1; 00301 } 00302 00303 /* init bestVis with first visual info */ 00304 get_visual_attribs(dpy, &visuals[0], &bestVis); 00305 00306 /* try to find a "better" visual */ 00307 for (i = 1; i < numVisuals; i++) { 00308 struct visual_attribs vis; 00309 00310 get_visual_attribs(dpy, &visuals[i], &vis); 00311 00312 /* always skip visuals with caveats */ 00313 if (vis.visualCaveat != GLX_NONE_EXT) 00314 continue; 00315 00316 /* see if this vis is better than bestVis */ 00317 if ((!bestVis.supportsGL && vis.supportsGL) || 00318 (bestVis.visualCaveat != GLX_NONE_EXT) || 00319 (!bestVis.rgba && vis.rgba) || 00320 (!bestVis.doubleBuffer && vis.doubleBuffer) || 00321 (bestVis.redSize < vis.redSize) || 00322 (bestVis.greenSize < vis.greenSize) || 00323 (bestVis.blueSize < vis.blueSize) || 00324 (bestVis.alphaSize < vis.alphaSize) || 00325 (bestVis.depthSize < vis.depthSize) || 00326 (bestVis.stencilSize < vis.stencilSize) || 00327 (bestVis.accumRedSize < vis.accumRedSize)) { 00328 /* found a better visual */ 00329 bestVis = vis; 00330 } 00331 } 00332 00333 XFree(visuals); 00334 00335 return bestVis.id; 00336 } 00337 00338 }; 00339 00340 void GLXWindow::create(const String& name, unsigned int width, unsigned int height, unsigned int colourDepth, 00341 bool fullScreen, int left, int top, bool depthBuffer, 00342 void* miscParam, ...) { 00343 std::cerr << "GLXWindow::create" << std::endl; 00344 00345 // We will attempt to create new window on default screen op display 0 00346 int screen = DefaultScreen(mDisplay); 00347 int depth = DisplayPlanes(mDisplay, screen); 00348 Window rootWindow = RootWindow(mDisplay,screen); 00349 #ifndef NO_XRANDR 00350 // Attempt mode switch for fullscreen -- only if RANDR extension is there 00351 int dummy; 00352 if(fullScreen && ! XQueryExtension(mDisplay, "RANDR", &dummy, &dummy, &dummy)) { 00353 LogManager::getSingleton().logMessage("GLXWindow::create -- Could not switch to full screen mode: No XRANDR extension found"); 00354 } else if(fullScreen) { 00355 // Use Xrandr extension to switch video modes. This is much better than 00356 // XVidMode as you can't scroll away from the full-screen applications. 00357 XRRScreenConfiguration *config; 00358 XRRScreenSize *sizes; 00359 Rotation current_rotation; 00360 int current_size; 00361 int nsizes; 00362 00363 // Get current screen info 00364 config = XRRGetScreenInfo(mDisplay, rootWindow); 00365 // Get available sizes 00366 if(config) 00367 sizes = XRRConfigSizes (config, &nsizes); 00368 00369 if(config && nsizes > 0) { 00370 // Get current size and rotation 00371 mOldMode = XRRConfigCurrentConfiguration (config, ¤t_rotation); 00372 // Find smallest matching mode 00373 int mode = -1; 00374 int mode_width = INT_MAX; 00375 int mode_height = INT_MAX; 00376 for(int i=0; i<nsizes; i++) { 00377 if(sizes[i].width >= width && sizes[i].height >= height && 00378 sizes[i].width < mode_width && sizes[i].height < mode_height) { 00379 mode = i; 00380 mode_width = sizes[i].width; 00381 mode_height = sizes[i].height; 00382 } 00383 } 00384 if(mode >= 0) { 00385 // Finally, set the screen configuration 00386 LogManager::getSingleton().logMessage("GLXWindow::create -- Entering full screen mode"); 00387 XRRSetScreenConfig(mDisplay, config, rootWindow, mode, current_rotation, CurrentTime); 00388 } else { 00389 LogManager::getSingleton().logMessage("GLXWindow::create -- Could not switch to full screen mode: No conforming mode was found"); 00390 } 00391 // Free configuration data 00392 XRRFreeScreenConfigInfo(config); 00393 } else { 00394 LogManager::getSingleton().logMessage("GLXWindow::create -- Could not switch to full screen mode: XRRGetScreenInfo failed"); 00395 } 00396 } 00397 #endif 00398 // Apply some magic algorithm to get the best visual 00399 int best_visual = find_best_visual(mDisplay, screen); 00400 LogManager::getSingleton().logMessage("GLXWindow::create -- Best visual is "+StringConverter::toString(best_visual)); 00401 00402 // Get information about this so-called-best visual 00403 XVisualInfo templ; 00404 int nmatch; 00405 templ.visualid = best_visual; 00406 XVisualInfo *visualInfo = XGetVisualInfo(mDisplay, VisualIDMask, &templ, &nmatch); 00407 if(visualInfo==0 || nmatch==0) { 00408 Except(999, "GLXWindow: error choosing visual", "GLXWindow::create"); 00409 } 00410 00411 XSetWindowAttributes attr; 00412 unsigned long mask; 00413 attr.background_pixel = 0; 00414 attr.border_pixel = 0; 00415 attr.colormap = XCreateColormap(mDisplay,rootWindow,visualInfo->visual,AllocNone); 00416 attr.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask; 00417 if(fullScreen) { 00418 mask = CWBackPixel | CWColormap | CWOverrideRedirect | CWSaveUnder | CWBackingStore | CWEventMask; 00419 attr.override_redirect = True; 00420 attr.backing_store = NotUseful; 00421 attr.save_under = False; 00422 // Fullscreen windows are always in the top left origin 00423 left = top = 0; 00424 } else 00425 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; 00426 00427 // Create window on server 00428 mWindow = XCreateWindow(mDisplay,rootWindow,left,top,width,height,0,visualInfo->depth,InputOutput,visualInfo->visual,mask,&attr); 00429 if(!mWindow) { 00430 Except(999, "GLXWindow: XCreateWindow failed", "GLXWindow::create"); 00431 } 00432 00433 // Make sure the window is in normal state 00434 XWMHints *wm_hints; 00435 if ((wm_hints = XAllocWMHints()) != NULL) { 00436 wm_hints->initial_state = NormalState; 00437 wm_hints->input = True; 00438 wm_hints->flags = StateHint | InputHint; 00439 00440 // Check if we can give it an icon 00441 if(depth == 24 || depth == 32) { 00442 // Woot! The right bit depth, we can load an icon 00443 if(LoadIcon(mDisplay, rootWindow, "GLX_icon.png", &wm_hints->icon_pixmap, &wm_hints->icon_mask)) 00444 wm_hints->flags |= IconPixmapHint | IconMaskHint; 00445 } 00446 } 00447 00448 // Set size and location hints 00449 XSizeHints *size_hints; 00450 if ((size_hints = XAllocSizeHints()) != NULL) { 00451 // Otherwise some window managers ignore our position request 00452 size_hints->flags = USPosition; 00453 } 00454 00455 // Make text property from title 00456 XTextProperty titleprop; 00457 char *lst = (char*)name.c_str(); 00458 XStringListToTextProperty((char **)&lst, 1, &titleprop); 00459 00460 XSetWMProperties(mDisplay, mWindow, &titleprop, NULL, NULL, 0, size_hints, wm_hints, NULL); 00461 00462 // We don't like memory leaks. Free the clientside storage, but not the 00463 // pixmaps as they're still being used by the server. 00464 XFree(titleprop.value); 00465 XFree(wm_hints); 00466 XFree(size_hints); 00467 00468 // Acquire atom to recognize window close events 00469 mAtomDeleteWindow = XInternAtom(mDisplay,"WM_DELETE_WINDOW",False); 00470 XSetWMProtocols(mDisplay,mWindow,&mAtomDeleteWindow,1); 00471 00472 // Map window unto screen and focus it. 00473 XMapWindow(mDisplay,mWindow); 00474 00475 // Make sure the server is up to date and focus the window 00476 XFlush(mDisplay); 00477 00478 // Finally, create a GL context 00479 mGlxContext = glXCreateContext(mDisplay,visualInfo,NULL,True); 00480 if(!mGlxContext) { 00481 Except(999, "glXCreateContext failed", "GLXWindow::create"); 00482 } 00483 glXMakeCurrent(mDisplay,mWindow,mGlxContext); 00484 00485 // Free visual info 00486 XFree(visualInfo); 00487 00488 mName = name; 00489 mWidth = width; 00490 mHeight = height; 00491 mFullScreen = fullScreen; 00492 } 00493 00494 void GLXWindow::destroy(void) { 00495 if(mGlxContext) 00496 glXDestroyContext(mDisplay, mGlxContext); 00497 if(mWindow) 00498 XDestroyWindow(mDisplay, mWindow); 00499 mWindow = 0; 00500 mGlxContext = 0; 00501 mActive = false; 00502 00503 Root::getSingleton().getRenderSystem()->detachRenderTarget( this->getName() ); 00504 } 00505 00506 bool GLXWindow::isActive() const { 00507 return mActive; 00508 } 00509 00510 bool GLXWindow::isClosed() const { 00511 return mClosed; 00512 } 00513 00514 void GLXWindow::reposition(int left, int top) { 00515 XMoveWindow(mDisplay,mWindow,left,top); 00516 } 00517 00518 void GLXWindow::resize(unsigned int width, unsigned int height) { 00519 XResizeWindow(mDisplay,mWindow,width,height); 00520 } 00521 00522 void GLXWindow::swapBuffers(bool waitForVSync) { 00523 glXSwapBuffers(mDisplay,mWindow); 00524 } 00525 00526 void GLXWindow::processEvent(const XEvent &event) { 00527 // Process only events for this window 00528 switch(event.type) { 00529 case ClientMessage: 00530 if(event.xclient.display != mDisplay || event.xclient.window != mWindow) 00531 // Not for me 00532 break; 00533 if(event.xclient.format == 32 && event.xclient.data.l[0] == (long)mAtomDeleteWindow) { 00534 // Window deleted -- oops, this does not work, ogre doesn't register the close 00535 //mClosed = true; 00536 //mActive = false; 00537 //Root::getSingleton().getRenderSystem()->detachRenderTarget( this->getName() ); 00538 } 00539 break; 00540 case ConfigureNotify: 00541 if(event.xconfigure.display != mDisplay || event.xconfigure.window != mWindow) 00542 // Not for me 00543 break; 00544 // Check if the window size really changed 00545 if(mWidth == event.xconfigure.width && mHeight == event.xconfigure.height) 00546 break; 00547 mWidth = event.xconfigure.width; 00548 mHeight = event.xconfigure.height; 00549 00550 for (ViewportList::iterator it = mViewportList.begin(); 00551 it != mViewportList.end(); ++it) { 00552 (*it).second->_updateDimensions(); 00553 } 00554 00555 break; 00556 case MapNotify: 00557 if(event.xconfigure.display != mDisplay || event.xconfigure.window != mWindow) 00558 // Not for me 00559 break; 00560 // Window was mapped to the screen 00561 mActive = true; 00562 break; 00563 case UnmapNotify: 00564 if(event.xconfigure.display != mDisplay || event.xconfigure.window != mWindow) 00565 // Not for me 00566 break; 00567 // Window was unmapped from the screen (user switched 00568 // to another workspace, for example) 00569 mActive = false; 00570 break; 00571 } 00572 } 00573 00574 00575 void GLXWindow::getCustomAttribute( const String& name, void* pData ) { 00576 if( name == "GLXWINDOW" ) { 00577 *static_cast<Window*>(pData) = mWindow; 00578 return; 00579 } else if( name == "GLXDISPLAY" ) { 00580 *static_cast<Display**>(pData) = mDisplay; 00581 return; 00582 } 00583 RenderWindow::getCustomAttribute(name, pData); 00584 } 00585 00586 void GLXWindow::writeContentsToFile(const String& filename) { 00587 00588 ImageCodec::ImageData imgData; 00589 imgData.width = mWidth; 00590 imgData.height = mHeight; 00591 imgData.format = PF_R8G8B8; 00592 00593 // Allocate buffer 00594 uchar* pBuffer = new uchar[mWidth * mHeight * 3]; 00595 00596 // Read pixels 00597 // I love GL: it does all the locking & colour conversion for us 00598 glReadPixels(0,0, mWidth-1, mHeight-1, GL_RGB, GL_UNSIGNED_BYTE, pBuffer); 00599 00600 // Wrap buffer in a chunk 00601 DataChunk chunk(pBuffer, mWidth * mHeight * 3); 00602 00603 // Need to flip the read data over in Y though 00604 Image img; 00605 img.loadRawData(chunk, mWidth, mHeight, PF_R8G8B8 ); 00606 img.flipAroundX(); 00607 00608 DataChunk chunkFlipped(img.getData(), chunk.getSize()); 00609 00610 // Get codec 00611 size_t pos = filename.find_last_of("."); 00612 String extension; 00613 if( pos == String::npos ) 00614 Except( 00615 Exception::ERR_INVALIDPARAMS, 00616 "Unable to determine image type for '" + filename + "' - invalid extension.", 00617 "GLXWindow::writeContentsToFile" ); 00618 00619 while( pos != filename.length() - 1 ) 00620 extension += filename[++pos]; 00621 00622 // Get the codec 00623 Codec * pCodec = Codec::getCodec(extension); 00624 00625 // Write out 00626 pCodec->codeToFile(chunkFlipped, filename, &imgData); 00627 00628 delete [] pBuffer; 00629 00630 00631 } 00632 }
Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:27 2004