source: OGRE/trunk/ogrenew/RenderSystems/GL/src/GLX/OgreGLXWindow.cpp @ 692

Revision 692, 18.2 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

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