Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/RenderSystems/GL/src/GLX/OgreGLXWindow.cpp @ 1

Last change on this file since 1 was 1, checked in by landauf, 17 years ago
File size: 18.7 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29
30#include "OgreGLXWindow.h"
31#include "OgreRoot.h"
32#include "OgreGLRenderSystem.h"
33#include "OgreImageCodec.h"
34#include "OgreException.h"
35#include "OgreLogManager.h"
36#include "OgreStringConverter.h"
37#include "OgreGLXUtils.h"
38#include "OgreWindowEventUtilities.h"
39
40#include <iostream>
41#include <algorithm>
42#include <sys/time.h>
43#include <climits>
44
45#include <X11/Xlib.h>
46#include <X11/keysym.h>
47
48#ifndef NO_XRANDR
49#include <X11/extensions/Xrandr.h>
50#endif
51
52#include <GL/gl.h>
53#include <GL/glu.h>
54#include <GL/glx.h>
55
56
57namespace Ogre
58{
59
60//-------------------------------------------------------------------------------------------------//
61GLXWindow::GLXWindow(Display *display) :
62        mDisplay(display), mWindow(0), mGlxContext(0), mVisualInfo(0), mDelVisualInfo(false), 
63        mDelWindow(false), mClosed(false), mVisible(true), mOldMode(-1),
64        mContext(0)
65{
66        mActive = false;
67        mIsFullScreen = false;
68}
69
70//-------------------------------------------------------------------------------------------------//
71GLXWindow::~GLXWindow() 
72{
73        if (mDelVisualInfo && mVisualInfo)
74                XFree(mVisualInfo);
75
76        if(mGlxContext)
77                glXDestroyContext(mDisplay, mGlxContext);
78       
79        if(mDelWindow && mWindow)
80                XDestroyWindow(mDisplay, mWindow);
81
82#ifndef NO_XRANDR
83        if(mIsFullScreen) 
84        {
85                // Restore original video mode.
86                Window rootWindow = DefaultRootWindow(mDisplay);
87                XRRScreenConfiguration *config;
88
89                // Get current screen info
90                config = XRRGetScreenInfo(mDisplay, rootWindow);
91                if(config) 
92                {
93                        Rotation current_rotation;
94                        XRRConfigCurrentConfiguration (config, &current_rotation);
95                        //std::cerr << "Restore mode " << mOldMode << std::endl;
96                        LogManager::getSingleton().logMessage("GLXWindow::~GLXWindow -- Leaving full screen mode");
97                        XRRSetScreenConfig(mDisplay, config, rootWindow, mOldMode, current_rotation, CurrentTime);
98                        XRRFreeScreenConfigInfo(config);
99                } 
100                else 
101                {
102                        LogManager::getSingleton().logMessage("GLXWindow::~GLXWindow -- Could not switch from full screen mode: XRRGetScreenInfo failed");
103                }
104        }
105#endif
106}
107
108//-------------------------------------------------------------------------------------------------//
109void GLXWindow::create(const String& name, unsigned int width, unsigned int height,
110                    bool fullScreen, const NameValuePairList *miscParams)
111{
112        LogManager::getSingleton().logMessage("GLXWindow::create");
113
114        String title = name;
115        size_t fsaa_samples = 0;
116
117        // We will attempt to create new window on default screen op display 0
118        // unless external window handle passed below
119        int screen = DefaultScreen(mDisplay);
120        int depth = DisplayPlanes(mDisplay, screen);
121        Window rootWindow = RootWindow(mDisplay,screen);
122        Window parentWindow = rootWindow;
123
124        // Make sure the window is centered if no left and top in parameters
125        size_t left = (int)DisplayWidth(mDisplay, screen)/2 - width/2;
126        size_t top = (int)DisplayHeight(mDisplay, screen)/2 - height/2;
127       
128        // Maybe user already created the window and passed its visualinfo in miscParams
129        XVisualInfo *   extVisualHandler = NULL;
130
131        // Unless parentWindowHandle is given in miscParams we're top-level
132        mTopLevel = true;
133   
134        LogManager::getSingleton().logMessage("Parsing miscParams");
135        if(miscParams)
136        {
137                // Parse miscellenous parameters
138                NameValuePairList::const_iterator opt;
139                // Full screen anti aliasing
140                opt = miscParams->find("FSAA");
141                if(opt != miscParams->end()) //check for FSAA parameter, if not ignore it...
142                        fsaa_samples = StringConverter::parseUnsignedInt(opt->second);
143                // left (x)
144                opt = miscParams->find("left");
145                if(opt != miscParams->end())
146                        left = StringConverter::parseUnsignedInt(opt->second);
147                // top (y)
148                opt = miscParams->find("top");
149                if(opt != miscParams->end())
150                        top = StringConverter::parseUnsignedInt(opt->second);
151                // Window title
152                opt = miscParams->find("title");
153                if(opt != miscParams->end()) //check for FSAA parameter, if not ignore it...
154                        title = opt->second;
155                opt = miscParams->find("parentWindowHandle");
156                if(opt != miscParams->end()) {  // embedding OGRE
157                        std::vector<String> tokens = StringUtil::split(opt->second, " :");
158                        String new_display = tokens[0];
159                        String new_screen = tokens[1];
160                        String wid = tokens[2];
161
162                        // Now set things to their correct values
163                        // This must be the ugliest line of code I have ever written :P
164                        mDisplay = reinterpret_cast<Display*>(StringConverter::parseUnsignedLong(new_display));
165                        screen = StringConverter::parseUnsignedInt(new_screen);
166                        parentWindow = StringConverter::parseUnsignedLong(wid);
167
168                        depth = DisplayPlanes(mDisplay, screen);
169                        rootWindow = RootWindow(mDisplay, screen);
170
171                        left = top = 0;
172                        fullScreen = false; // Can't be full screen if embedded in an app!
173                }
174               
175                opt = miscParams->find("externalWindowHandle");
176                if(opt != miscParams->end()) // embedding OGRE in already created window
177                {
178                        std::vector<String> tokens = StringUtil::split(opt->second, " :");
179                        String new_display = tokens[0];
180                        String new_screen = tokens[1];
181                        String wid = tokens[2];
182                       
183                        mDisplay = reinterpret_cast<Display*>(StringConverter::parseUnsignedLong(new_display)); 
184                        screen = StringConverter::parseUnsignedInt(new_screen); 
185                        mWindow = StringConverter::parseUnsignedLong(wid);
186                       
187                        if(tokens.size() > 3) // external visual was already setup
188                        {
189                                extVisualHandler = reinterpret_cast<XVisualInfo*>(StringConverter::parseUnsignedLong(tokens[3]));
190                        }
191                       
192                        depth = DisplayPlanes(mDisplay, screen);
193                        rootWindow = RootWindow(mDisplay, screen);
194                       
195                        left = top = 0;
196                        fullScreen = false; // Can't be full screen if embedded in an app!
197                        mTopLevel = false;  // Can't be top-level if embedded         
198                }
199
200        }
201
202        // Check for full screen mode if FSAA was asked for
203        if(!fullScreen && fsaa_samples>0)
204        {
205                LogManager::getSingleton().logMessage("GLXWindow::create -- FSAA only supported in fullscreen mode");
206                fsaa_samples = 0;
207        }
208        // Disable FSAA for now -- it doesn't work on NVIDIA
209        fsaa_samples = 0;
210
211#ifndef NO_XRANDR
212        // Attempt mode switch for fullscreen -- only if RANDR extension is there
213        int dummy;
214        if(fullScreen && ! XQueryExtension(mDisplay, "RANDR", &dummy, &dummy, &dummy)) 
215        {
216                LogManager::getSingleton().logMessage("GLXWindow::create -- Could not switch to full screen mode: No XRANDR extension found");
217        } 
218        else if(fullScreen) 
219        {
220                // Use Xrandr extension to switch video modes. This is much better than
221                // XVidMode as you can't scroll away from the full-screen applications.
222                XRRScreenConfiguration *config;
223                XRRScreenSize *sizes;
224                Rotation current_rotation;
225                int nsizes;
226
227                // Get current screen info
228                config = XRRGetScreenInfo(mDisplay, rootWindow);
229                // Get available sizes
230                if(config)
231                        sizes = XRRConfigSizes (config, &nsizes);
232
233                if(config && nsizes > 0) {
234                        // Get current size and rotation
235                        mOldMode = XRRConfigCurrentConfiguration (config, &current_rotation);
236                        // Find smallest matching mode
237                        int mode = -1;
238                        int mode_width = INT_MAX;
239                        int mode_height = INT_MAX;
240                        for(size_t i=0; i<nsizes; i++) 
241                        {
242                                if(sizes[i].width >= static_cast<int>(width) && 
243                                        sizes[i].height >= static_cast<int>(height) &&
244                                    sizes[i].width < mode_width && 
245                                        sizes[i].height < mode_height) 
246                                {
247                                        mode = i;
248                                        mode_width = sizes[i].width;
249                                        mode_height = sizes[i].height;
250                                }
251                        }
252                        if(mode >= 0) {
253                                // Finally, set the screen configuration
254                                LogManager::getSingleton().logMessage("GLXWindow::create -- Entering full screen mode");
255                                XRRSetScreenConfig(mDisplay, config, rootWindow, mode, current_rotation, CurrentTime);
256                        } else {
257                                LogManager::getSingleton().logMessage("GLXWindow::create -- Could not switch to full screen mode: No conforming mode was found");
258                        }
259                        // Free configuration data
260                        XRRFreeScreenConfigInfo(config);
261                } else {
262                        LogManager::getSingleton().logMessage("GLXWindow::create -- Could not switch to full screen mode: XRRGetScreenInfo failed");
263                }
264        }
265#endif
266
267        if(extVisualHandler == NULL) // user didn't create visual ( and window ) himself
268        {
269                // Apply some magic algorithm to get the best visual
270                int best_visual = GLXUtils::findBestVisual(mDisplay, screen, fsaa_samples);
271                if(best_visual == -1)
272                {
273                        best_visual = GLXUtils::findBestVisual(mDisplay, screen);
274                        LogManager::getSingleton().logMessage("GLXWindow::create -- Requested FSAA of "+
275                                        StringConverter::toString(fsaa_samples)+" was not acquirable, defaulting to first suitable visual");
276                }
277                LogManager::getSingleton().logMessage("GLXWindow::create -- Best visual is "+StringConverter::toString(best_visual));
278
279                // Get information about this so-called-best visual
280                XVisualInfo templ;
281                int nmatch;
282                templ.visualid = best_visual;
283                mVisualInfo = XGetVisualInfo(mDisplay, VisualIDMask, &templ, &nmatch);
284                mDelVisualInfo = true;
285                if(mVisualInfo==0 || nmatch==0) {
286                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "GLXWindow: error choosing visual", "GLXWindow::create");
287                }
288
289                XSetWindowAttributes attr;
290                unsigned long mask;
291                attr.background_pixel = 0;
292                attr.border_pixel = 0;
293                attr.colormap = XCreateColormap(mDisplay,rootWindow,mVisualInfo->visual,AllocNone);
294                attr.event_mask = StructureNotifyMask | VisibilityChangeMask;
295                if(fullScreen) {
296                        mask = CWBackPixel | CWColormap | CWOverrideRedirect | CWSaveUnder | CWBackingStore | CWEventMask;
297                        attr.override_redirect = True;
298                        attr.backing_store = NotUseful;
299                        attr.save_under = False;
300                        // Fullscreen windows are always in the top left origin
301                        left = top = 0;
302                } else
303                        mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
304       
305                // Create window on server
306                mWindow = XCreateWindow(mDisplay,parentWindow,left,top,width,height,0,mVisualInfo->depth,InputOutput,mVisualInfo->visual,mask,&attr);
307                mDelWindow = true;
308                if(!mWindow) {
309                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "GLXWindow: XCreateWindow failed", "GLXWindow::create");
310                }
311       
312                // Make sure the window is in normal state
313                XWMHints *wm_hints;
314                if ((wm_hints = XAllocWMHints()) != NULL) {
315                        wm_hints->initial_state = NormalState;
316                        wm_hints->input = True;
317                        wm_hints->flags = StateHint | InputHint;
318       
319                        // Check if we can give it an icon
320                        if(depth == 24 || depth == 32) {
321                                // Woot! The right bit depth, we can load an icon
322                                if(GLXUtils::LoadIcon(mDisplay, rootWindow, "GLX_icon.png", &wm_hints->icon_pixmap, &wm_hints->icon_mask))
323                                        wm_hints->flags |= IconPixmapHint | IconMaskHint;
324                        }
325                }
326       
327                // Set size and location hints
328                XSizeHints *size_hints;
329                if ((size_hints = XAllocSizeHints()) != NULL) {
330                        // Otherwise some window managers ignore our position request
331                        size_hints->flags = USPosition;
332                }
333       
334                // Make text property from title
335                XTextProperty titleprop;
336                char *lst = (char*)title.c_str();
337                XStringListToTextProperty((char **)&lst, 1, &titleprop);
338       
339                XSetWMProperties(mDisplay, mWindow, &titleprop, NULL, NULL, 0, size_hints, wm_hints, NULL);
340       
341                // We don't like memory leaks. Free the clientside storage, but not the
342                // pixmaps as they're still being used by the server.
343                XFree(titleprop.value);
344                XFree(wm_hints);
345                XFree(size_hints);
346       
347                // Acquire atom to recognize window close events
348                mAtomDeleteWindow = XInternAtom(mDisplay,"WM_DELETE_WINDOW",False);
349                XSetWMProtocols(mDisplay,mWindow,&mAtomDeleteWindow,1);
350       
351                // Map window unto screen and focus it.
352                XMapWindow(mDisplay,mWindow);
353       
354                // Make sure the server is up to date and focus the window
355                XFlush(mDisplay);
356
357                //Register only Ogre created windows (users can register their own)
358                WindowEventUtilities::_addRenderWindow(this);
359        }
360        else
361        {
362                LogManager::getSingleton().logMessage("GLXWindow::create -- using external window handle");
363                mVisualInfo = extVisualHandler;
364                mDelVisualInfo = false;
365        }
366
367        GLRenderSystem *rs = static_cast<GLRenderSystem*>(Root::getSingleton().getRenderSystem());
368        GLXContext* mainContext = static_cast<GLXContext*>( rs->_getMainContext() );
369        if ( mainContext == 0 )
370        {
371                // Finally, create a GL context
372                // we want to share it with main
373                mGlxContext = glXCreateContext(mDisplay,mVisualInfo,NULL,True);
374        }
375                else
376                        mGlxContext = glXCreateContext(mDisplay,mVisualInfo,mainContext->mCtx,True);
377       
378        if(!mGlxContext)
379                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "glXCreateContext failed", "GLXWindow::create");
380
381        mName = name;
382        mWidth = width;
383        mHeight = height;
384        mIsFullScreen = fullScreen;
385
386        //Get the attributes of the screen
387        XWindowAttributes temp;
388        XGetWindowAttributes(mDisplay, mWindow, &temp);
389        mLeft = temp.x;
390        mTop = temp.y;
391
392        // Create OGRE GL context
393        mContext = new GLXContext(mDisplay, mWindow, mGlxContext, mVisualInfo);
394}
395
396//-------------------------------------------------------------------------------------------------//
397void GLXWindow::destroy(void)
398{
399        WindowEventUtilities::_removeRenderWindow(this);
400
401        // Unregister and destroy OGRE GLContext
402        delete mContext;
403
404        // Destroy GL context
405        if(mGlxContext)
406                glXDestroyContext(mDisplay, mGlxContext);
407
408        if(mDelWindow && mWindow)
409                XDestroyWindow(mDisplay, mWindow);
410
411        mContext = 0;
412        mWindow = 0;
413        mGlxContext = 0;
414        mActive = false;
415        mVisible = false;
416        mClosed = true;
417
418        Root::getSingleton().getRenderSystem()->detachRenderTarget( this->getName() );
419}
420
421//-------------------------------------------------------------------------------------------------//
422bool GLXWindow::isActive() const
423{
424        return mActive;
425}
426
427//-------------------------------------------------------------------------------------------------//
428bool GLXWindow::isClosed() const
429{
430        return mClosed;
431}
432
433//-------------------------------------------------------------------------------------------------//
434bool GLXWindow::isVisible() const
435{
436        return mVisible;
437}
438
439//-------------------------------------------------------------------------------------------------//
440void GLXWindow::setVisible(bool visible)
441{
442        mVisible = visible;
443}
444
445//-------------------------------------------------------------------------------------------------//
446void GLXWindow::reposition(int left, int top)
447{
448        XMoveWindow(mDisplay,mWindow,left,top);
449}
450
451//-------------------------------------------------------------------------------------------------//
452void GLXWindow::resize(unsigned int width, unsigned int height)
453{
454        // Check if the window size really changed
455        if(mWidth == width && mHeight == height)
456                return;
457
458        mWidth = width;
459        mHeight = height;
460
461        if (!mTopLevel)
462        {
463                for (ViewportList::iterator it = mViewportList.begin(); it != mViewportList.end(); ++it)
464                        (*it).second->_updateDimensions();
465        }
466        else
467        {
468                XResizeWindow(mDisplay, mWindow, width, height); /// Ogre handles window
469        }
470}
471
472//-------------------------------------------------------------------------------------------------//
473void GLXWindow::windowMovedOrResized()
474{
475        //Get the new attributes of the screen
476        XWindowAttributes temp;
477        XGetWindowAttributes(mDisplay, mWindow, &temp);
478        mLeft = temp.x;
479        mTop  = temp.y;
480
481        //Only update viewport dimensions if they did actually change
482        if (static_cast<int>(mWidth) == temp.width && static_cast<int>(mHeight) == temp.height)
483                return;
484
485        mWidth = temp.width;
486        mHeight = temp.height;
487
488        // Notify viewports of resize
489        ViewportList::iterator it, itend;
490        itend = mViewportList.end();
491        for( it = mViewportList.begin(); it != itend; ++it )
492                (*it).second->_updateDimensions();
493}
494
495//-------------------------------------------------------------------------------------------------//
496void GLXWindow::swapBuffers(bool waitForVSync)
497{
498        glXSwapBuffers(mDisplay,mWindow);
499}
500
501//-------------------------------------------------------------------------------------------------//
502void GLXWindow::getCustomAttribute( const String& name, void* pData )
503{
504        if( name == "DISPLAY" ) 
505        {
506                *static_cast<Display**>(pData) = mDisplay;
507                return;
508        }
509        else if( name == "ATOM" ) 
510        {
511                *static_cast< ::Atom* >(pData) = mAtomDeleteWindow;
512                return;
513        } 
514        else if( name == "WINDOW" ) 
515        {
516                *static_cast<Window*>(pData) = mWindow;
517                return;
518        } 
519        else if( name == "GLCONTEXT" ) 
520        {
521                *static_cast<GLXContext**>(pData) = mContext;
522                return;
523        } 
524}
525
526//-------------------------------------------------------------------------------------------------//
527void GLXWindow::writeContentsToFile(const String& filename)
528{
529        ImageCodec::ImageData* imgData = new ImageCodec::ImageData;
530        imgData->width = mWidth;
531        imgData->height = mHeight;
532        imgData->format = PF_BYTE_RGB;
533
534        // Allocate buffer
535        uchar* pBuffer = new uchar[mWidth * mHeight * 3];
536
537        // Read pixels
538        // I love GL: it does all the locking & colour conversion for us
539        glReadPixels(0,0, mWidth, mHeight, GL_RGB, GL_UNSIGNED_BYTE, pBuffer);
540
541        // Wrap buffer in a memory stream
542        DataStreamPtr stream(new MemoryDataStream(pBuffer, mWidth * mHeight * 3, false));
543
544        // Need to flip the read data over in Y though
545        Image img;
546        img.loadRawData(stream, mWidth, mHeight, PF_BYTE_RGB );
547        img.flipAroundX();
548
549        MemoryDataStreamPtr streamFlipped(new MemoryDataStream(img.getData(), stream->size(), false));
550
551        // Get codec
552        size_t pos = filename.find_last_of(".");
553        String extension;
554        if( pos == String::npos )
555                OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, "Unable to determine image type for '" 
556                        + filename + "' - invalid extension.", "SDLWindow::writeContentsToFile" );
557
558        while( pos != filename.length() - 1 )
559                extension += filename[++pos];
560
561        // Get the codec
562        Codec * pCodec = Codec::getCodec(extension);
563
564        // Write out
565        Codec::CodecDataPtr codecDataPtr(imgData);
566        pCodec->codeToFile(streamFlipped, filename, codecDataPtr);
567
568        delete [] pBuffer;
569}
570}
Note: See TracBrowser for help on using the repository browser.