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

Revision 657, 17.9 KB checked in by mattausch, 18 years ago (diff)

added ogre dependencies and patched ogre sources

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