Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/RenderSystems/GL/src/OgreWin32GLSupport.cpp @ 1

Last change on this file since 1 was 1, checked in by landauf, 17 years ago
File size: 18.3 KB
Line 
1#include "OgreRoot.h"
2#include "OgreException.h"
3#include "OgreLogManager.h"
4#include "OgreStringConverter.h"
5
6#include <algorithm>
7
8#include "OgreWin32GLSupport.h"
9#include "OgreGLTexture.h"
10#include "OgreWin32Window.h"
11#include <GL/wglext.h>
12#include "OgreWin32RenderTexture.h"
13
14using namespace Ogre;
15
16GLenum wglewContextInit (Ogre::GLSupport *glSupport);
17
18namespace Ogre {
19        Win32GLSupport::Win32GLSupport()
20        : mInitialWindow(0)
21        , mHasPixelFormatARB(false)
22        , mHasMultisample(false)
23    {
24                // immediately test WGL_ARB_pixel_format and FSAA support
25                // so we can set configuration options appropriately
26                initialiseWGL();
27    } 
28
29        template<class C> void remove_duplicates(C& c)
30        {
31                std::sort(c.begin(), c.end());
32                typename C::iterator p = std::unique(c.begin(), c.end());
33                c.erase(p, c.end());
34        }
35
36        void Win32GLSupport::addConfig()
37        {
38                //TODO: EnumDisplayDevices http://msdn.microsoft.com/library/en-us/gdi/devcons_2303.asp
39                /*vector<string> DisplayDevices;
40                DISPLAY_DEVICE DisplayDevice;
41                DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
42                DWORD i=0;
43                while (EnumDisplayDevices(NULL, i++, &DisplayDevice, 0) {
44                        DisplayDevices.push_back(DisplayDevice.DeviceName);
45                }*/
46                 
47                ConfigOption optFullScreen;
48                ConfigOption optVideoMode;
49                ConfigOption optColourDepth;
50                ConfigOption optDisplayFrequency;
51                ConfigOption optVSync;
52                ConfigOption optFSAA;
53                ConfigOption optRTTMode;
54
55                // FS setting possiblities
56                optFullScreen.name = "Full Screen";
57                optFullScreen.possibleValues.push_back("Yes");
58                optFullScreen.possibleValues.push_back("No");
59                optFullScreen.currentValue = "Yes";
60                optFullScreen.immutable = false;
61
62                // Video mode possiblities
63                DEVMODE DevMode;
64                DevMode.dmSize = sizeof(DEVMODE);
65                optVideoMode.name = "Video Mode";
66                optVideoMode.immutable = false;
67                for (DWORD i = 0; EnumDisplaySettings(NULL, i, &DevMode); ++i)
68                {
69                        if (DevMode.dmBitsPerPel < 16 || DevMode.dmPelsHeight < 480)
70                                continue;
71                        mDevModes.push_back(DevMode);
72                        StringUtil::StrStreamType str;
73                        str << DevMode.dmPelsWidth << " x " << DevMode.dmPelsHeight;
74                        optVideoMode.possibleValues.push_back(str.str());
75                }
76                remove_duplicates(optVideoMode.possibleValues);
77                optVideoMode.currentValue = optVideoMode.possibleValues.front();
78
79                optColourDepth.name = "Colour Depth";
80                optColourDepth.immutable = false;
81                optColourDepth.currentValue.clear();
82
83                optDisplayFrequency.name = "Display Frequency";
84                optDisplayFrequency.immutable = false;
85        optDisplayFrequency.currentValue.clear();
86
87                optVSync.name = "VSync";
88                optVSync.immutable = false;
89                optVSync.possibleValues.push_back("No");
90                optVSync.possibleValues.push_back("Yes");
91                optVSync.currentValue = "No";
92
93                optFSAA.name = "FSAA";
94                optFSAA.immutable = false;
95                optFSAA.possibleValues.push_back("0");
96                for (std::vector<int>::iterator it = mFSAALevels.begin(); it != mFSAALevels.end(); ++it)
97                        optFSAA.possibleValues.push_back(StringConverter::toString(*it));
98                optFSAA.currentValue = "0";
99
100                optRTTMode.name = "RTT Preferred Mode";
101                optRTTMode.possibleValues.push_back("FBO");
102                optRTTMode.possibleValues.push_back("PBuffer");
103                optRTTMode.possibleValues.push_back("Copy");
104                optRTTMode.currentValue = "FBO";
105                optRTTMode.immutable = false;
106
107
108                mOptions[optFullScreen.name] = optFullScreen;
109                mOptions[optVideoMode.name] = optVideoMode;
110                mOptions[optColourDepth.name] = optColourDepth;
111                mOptions[optDisplayFrequency.name] = optDisplayFrequency;
112                mOptions[optVSync.name] = optVSync;
113                mOptions[optFSAA.name] = optFSAA;
114                mOptions[optRTTMode.name] = optRTTMode;
115
116                refreshConfig();
117        }
118
119        void Win32GLSupport::refreshConfig()
120        {
121                ConfigOptionMap::iterator optVideoMode = mOptions.find("Video Mode");
122                ConfigOptionMap::iterator moptColourDepth = mOptions.find("Colour Depth");
123                ConfigOptionMap::iterator moptDisplayFrequency = mOptions.find("Display Frequency");
124                if(optVideoMode == mOptions.end() || moptColourDepth == mOptions.end() || moptDisplayFrequency == mOptions.end())
125                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Can't find mOptions!", "Win32GLSupport::refreshConfig");
126                ConfigOption* optColourDepth = &moptColourDepth->second;
127                ConfigOption* optDisplayFrequency = &moptDisplayFrequency->second;
128
129                const String& val = optVideoMode->second.currentValue;
130                String::size_type pos = val.find('x');
131                if (pos == String::npos)
132                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid Video Mode provided", "Win32GLSupport::refreshConfig");
133                DWORD width = StringConverter::parseUnsignedInt(val.substr(0, pos));
134                DWORD height = StringConverter::parseUnsignedInt(val.substr(pos+1, String::npos));
135
136                for(std::vector<DEVMODE>::const_iterator i = mDevModes.begin(); i != mDevModes.end(); ++i)
137                {
138                        if (i->dmPelsWidth != width || i->dmPelsHeight != height)
139                                continue;
140                        optColourDepth->possibleValues.push_back(StringConverter::toString(i->dmBitsPerPel));
141                        optDisplayFrequency->possibleValues.push_back(StringConverter::toString(i->dmDisplayFrequency));
142                }
143                remove_duplicates(optColourDepth->possibleValues);
144                remove_duplicates(optDisplayFrequency->possibleValues);
145                optColourDepth->currentValue = optColourDepth->possibleValues.back();
146                if (optDisplayFrequency->currentValue != "N/A")
147                        optDisplayFrequency->currentValue = optDisplayFrequency->possibleValues.front();
148        }
149
150        void Win32GLSupport::setConfigOption(const String &name, const String &value)
151        {
152                ConfigOptionMap::iterator it = mOptions.find(name);
153
154                // Update
155                if(it != mOptions.end())
156                        it->second.currentValue = value;
157                else
158                {
159            StringUtil::StrStreamType str;
160            str << "Option named '" << name << "' does not exist.";
161                        OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, str.str(), "Win32GLSupport::setConfigOption" );
162                }
163
164                if( name == "Video Mode" )
165                        refreshConfig();
166
167                if( name == "Full Screen" )
168                {
169                        it = mOptions.find( "Display Frequency" );
170                        if( value == "No" )
171                        {
172                                it->second.currentValue = "N/A";
173                                it->second.immutable = true;
174                        }
175                        else
176                        {
177                                it->second.currentValue = it->second.possibleValues.front();
178                                it->second.immutable = false;
179                        }
180                }
181        }
182
183        String Win32GLSupport::validateConfig()
184        {
185                // TODO, DX9
186                return StringUtil::BLANK;
187        }
188
189        RenderWindow* Win32GLSupport::createWindow(bool autoCreateWindow, GLRenderSystem* renderSystem, const String& windowTitle)
190        {
191                if (autoCreateWindow)
192        {
193            ConfigOptionMap::iterator opt = mOptions.find("Full Screen");
194            if (opt == mOptions.end())
195                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Can't find full screen options!", "Win32GLSupport::createWindow");
196            bool fullscreen = (opt->second.currentValue == "Yes");
197
198            opt = mOptions.find("Video Mode");
199            if (opt == mOptions.end())
200                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Can't find video mode options!", "Win32GLSupport::createWindow");
201            String val = opt->second.currentValue;
202            String::size_type pos = val.find('x');
203            if (pos == String::npos)
204                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid Video Mode provided", "Win32GLSupport::createWindow");
205
206                        unsigned int w = StringConverter::parseUnsignedInt(val.substr(0, pos));
207            unsigned int h = StringConverter::parseUnsignedInt(val.substr(pos + 1));
208
209                        // Parse optional parameters
210                        NameValuePairList winOptions;
211                        opt = mOptions.find("Colour Depth");
212                        if (opt == mOptions.end())
213                                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Can't find Colour Depth options!", "Win32GLSupport::createWindow");
214                        unsigned int colourDepth =
215                                StringConverter::parseUnsignedInt(opt->second.currentValue);
216                        winOptions["colourDepth"] = StringConverter::toString(colourDepth);
217
218                        opt = mOptions.find("VSync");
219                        if (opt == mOptions.end())
220                                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Can't find VSync options!", "Win32GLSupport::createWindow");
221                        bool vsync = (opt->second.currentValue == "Yes");
222                        winOptions["vsync"] = StringConverter::toString(vsync);
223                        renderSystem->setWaitForVerticalBlank(vsync);
224
225                        opt = mOptions.find("Display Frequency");
226                        if (opt != mOptions.end())
227                        {
228                                unsigned int displayFrequency =
229                                        StringConverter::parseUnsignedInt(opt->second.currentValue);
230                                winOptions["displayFrequency"] = StringConverter::toString(displayFrequency);
231                        }
232
233                        opt = mOptions.find("FSAA");
234                        if (opt == mOptions.end())
235                                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Can't find FSAA options!", "Win32GLSupport::createWindow");
236                        unsigned int multisample =
237                                StringConverter::parseUnsignedInt(opt->second.currentValue);
238                        winOptions["FSAA"] = StringConverter::toString(multisample);
239
240            return renderSystem->createRenderWindow(windowTitle, w, h, fullscreen, &winOptions);
241        }
242        else
243        {
244            // XXX What is the else?
245                        return NULL;
246        }
247        }
248
249        RenderWindow* Win32GLSupport::newWindow(const String &name, unsigned int width, 
250                unsigned int height, bool fullScreen, const NameValuePairList *miscParams)
251        {
252                ConfigOptionMap::iterator opt = mOptions.find("Display Frequency");
253                if (opt == mOptions.end())
254                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Can't find Display Frequency options!", "Win32GLSupport::newWindow");
255                unsigned int displayFrequency = StringConverter::parseUnsignedInt(opt->second.currentValue);
256
257                Win32Window* window = new Win32Window(*this);
258                window->create(name, width, height, fullScreen, miscParams);
259
260                if(!mInitialWindow)
261                        mInitialWindow = window;
262                return window;
263        }
264
265        void Win32GLSupport::start()
266        {
267                LogManager::getSingleton().logMessage("*** Starting Win32GL Subsystem ***");
268        }
269
270        void Win32GLSupport::stop()
271        {
272                LogManager::getSingleton().logMessage("*** Stopping Win32GL Subsystem ***");
273                mInitialWindow = 0; // Since there is no removeWindow, although there should be...
274        }
275
276        void Win32GLSupport::initialiseExtensions()
277        {
278                assert(mInitialWindow);
279                // First, initialise the normal extensions
280                GLSupport::initialiseExtensions();
281                // wglew init
282                wglewContextInit(this);
283
284                // Check for W32 specific extensions probe function
285                PFNWGLGETEXTENSIONSSTRINGARBPROC _wglGetExtensionsStringARB = 
286                        (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
287                if(!_wglGetExtensionsStringARB)
288                        return;
289                const char *wgl_extensions = _wglGetExtensionsStringARB(mInitialWindow->getHDC());
290        StringUtil::StrStreamType str;
291        str << "Supported WGL extensions: " << wgl_extensions;
292                LogManager::getSingleton().logMessage(
293                        LML_NORMAL, str.str());
294                // Parse them, and add them to the main list
295                std::stringstream ext;
296        String instr;
297                ext << wgl_extensions;
298        while(ext >> instr)
299        {
300            extensionList.insert(instr);
301        }
302        }
303
304
305        void* Win32GLSupport::getProcAddress(const String& procname)
306        {
307                return (void*)wglGetProcAddress( procname.c_str() );
308        }
309/*
310        RenderTexture * Win32GLSupport::createRenderTexture( const String & name,
311                unsigned int width, unsigned int height,
312                TextureType texType, PixelFormat internalFormat,
313                const NameValuePairList *miscParams )
314        {
315#ifdef HW_RTT
316                bool useBind = checkExtension("WGL_ARB_render_texture");
317
318                if(Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_HWRENDER_TO_TEXTURE))
319                        return new Win32RenderTexture(*this, name, width, height, texType,
320                                internalFormat, miscParams, useBind);
321                else
322#endif
323                        return new GLRenderTexture(name, width, height, texType, internalFormat, miscParams);
324        }
325
326*/
327        void Win32GLSupport::initialiseWGL()
328        {
329                // wglGetProcAddress does not work without an active OpenGL context,
330                // but we need wglChoosePixelFormatARB's address before we can
331                // create our main window.  Thank you very much, Microsoft!
332                //
333                // The solution is to create a dummy OpenGL window first, and then
334                // test for WGL_ARB_pixel_format support.  If it is not supported,
335                // we make sure to never call the ARB pixel format functions.
336                //
337                // If is is supported, we call the pixel format functions at least once
338                // to initialise them (pointers are stored by glprocs.h).  We can also
339                // take this opportunity to enumerate the valid FSAA modes.
340               
341                LPCSTR dummyText = "OgreWglDummy";
342#ifdef OGRE_STATIC_LIB
343                HINSTANCE hinst = GetModuleHandle( NULL );
344#else
345                HINSTANCE hinst = GetModuleHandle("RenderSystem_GL.dll");
346#endif
347               
348                WNDCLASS dummyClass;
349                memset(&dummyClass, 0, sizeof(WNDCLASS));
350                dummyClass.style = CS_OWNDC;
351                dummyClass.hInstance = hinst;
352                dummyClass.lpfnWndProc = dummyWndProc;
353                dummyClass.lpszClassName = dummyText;
354                RegisterClass(&dummyClass);
355
356                HWND hwnd = CreateWindow(dummyText, dummyText,
357                        WS_POPUP | WS_CLIPCHILDREN,
358                        0, 0, 32, 32, 0, 0, hinst, 0);
359
360                // if a simple CreateWindow fails, then boy are we in trouble...
361                if (hwnd == NULL)
362                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "CreateWindow() failed", "Win32GLSupport::initializeWGL");
363
364
365                // no chance of failure and no need to release thanks to CS_OWNDC
366                HDC hdc = GetDC(hwnd); 
367
368                // assign a simple OpenGL pixel format that everyone supports
369                PIXELFORMATDESCRIPTOR pfd;
370                memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
371                pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
372                pfd.nVersion = 1;
373                pfd.cColorBits = 16;
374                pfd.cDepthBits = 15;
375                pfd.dwFlags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER;
376                pfd.iPixelType = PFD_TYPE_RGBA;
377               
378                // if these fail, wglCreateContext will also quietly fail
379                int format;
380                if ((format = ChoosePixelFormat(hdc, &pfd)) != 0)
381                        SetPixelFormat(hdc, format, &pfd);
382
383                HGLRC hrc = wglCreateContext(hdc);
384                if (hrc)
385                {
386                        HGLRC oldrc = wglGetCurrentContext();
387                        HDC oldhdc = wglGetCurrentDC();
388                        // if wglMakeCurrent fails, wglGetProcAddress will return null
389                        wglMakeCurrent(hdc, hrc);
390                       
391                        PFNWGLGETEXTENSIONSSTRINGARBPROC _wglGetExtensionsStringARB =
392                                (PFNWGLGETEXTENSIONSSTRINGARBPROC)
393                                wglGetProcAddress("wglGetExtensionsStringARB");
394                       
395                        // check for pixel format and multisampling support
396                        if (_wglGetExtensionsStringARB)
397                        {
398                                std::istringstream wglexts(_wglGetExtensionsStringARB(hdc));
399                                std::string ext;
400                                while (wglexts >> ext)
401                                {
402                                        if (ext == "WGL_ARB_pixel_format")
403                                                mHasPixelFormatARB = true;
404                                        else if (ext == "WGL_ARB_multisample")
405                                                mHasMultisample = true;
406                                }
407                        }
408
409                        if (mHasPixelFormatARB && mHasMultisample)
410                        {
411                                // enumerate all formats w/ multisampling
412                                static const int iattr[] = {
413                                        WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
414                                        WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
415                                        WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
416                                        WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
417                                        WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
418                    /* We are no matter about the colour, depth and stencil buffers here
419                                        WGL_COLOR_BITS_ARB, 24,
420                                        WGL_ALPHA_BITS_ARB, 8,
421                                        WGL_DEPTH_BITS_ARB, 24,
422                                        WGL_STENCIL_BITS_ARB, 8,
423                    */
424                                        WGL_SAMPLES_ARB, 2,
425                                        0
426                                };
427                                int formats[256];
428                                unsigned int count;
429                // cheating here.  wglChoosePixelFormatARB procc address needed later on
430                // when a valid GL context does not exist and glew is not initialized yet.
431                __wglewChoosePixelFormatARB =
432                    (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
433                if (__wglewChoosePixelFormatARB(hdc, iattr, 0, 256, formats, &count))
434                {
435                    // determine what multisampling levels are offered
436                    int query = WGL_SAMPLES_ARB, samples;
437                    for (unsigned int i = 0; i < count; ++i)
438                    {
439                        PFNWGLGETPIXELFORMATATTRIBIVARBPROC _wglGetPixelFormatAttribivARB =
440                            (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
441                            wglGetProcAddress("wglGetPixelFormatAttribivARB");
442                        if (_wglGetPixelFormatAttribivARB(hdc, formats[i], 0, 1, &query, &samples))
443                        {
444                            mFSAALevels.push_back(samples);
445                        }
446                    }
447                    remove_duplicates(mFSAALevels);
448                }
449                        }
450                       
451                        wglMakeCurrent(oldhdc, oldrc);
452                        wglDeleteContext(hrc);
453                }
454
455                // clean up our dummy window and class
456                DestroyWindow(hwnd);
457                UnregisterClass(dummyText, hinst);
458        }
459
460        LRESULT Win32GLSupport::dummyWndProc(HWND hwnd, UINT umsg, WPARAM wp, LPARAM lp)
461        {
462                return DefWindowProc(hwnd, umsg, wp, lp);
463        }
464
465        bool Win32GLSupport::selectPixelFormat(HDC hdc, int colourDepth, int multisample)
466        {
467                PIXELFORMATDESCRIPTOR pfd;
468                memset(&pfd, 0, sizeof(pfd));
469                pfd.nSize = sizeof(pfd);
470                pfd.nVersion = 1;
471                pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
472                pfd.iPixelType = PFD_TYPE_RGBA;
473                pfd.cColorBits = (colourDepth > 16)? 24 : colourDepth;
474                pfd.cAlphaBits = (colourDepth > 16)? 8 : 0;
475                pfd.cDepthBits = 24;
476                pfd.cStencilBits = 8;
477
478                int format = 0;
479
480                if (multisample)
481                {
482                        // only available with driver support
483                        if (!mHasMultisample || !mHasPixelFormatARB)
484                                return false;
485                       
486                        int iattr[] = {
487                                WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
488                                WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
489                                WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
490                                WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
491                                WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
492                                WGL_COLOR_BITS_ARB, pfd.cColorBits,
493                                WGL_ALPHA_BITS_ARB, pfd.cAlphaBits,
494                                WGL_DEPTH_BITS_ARB, 24,
495                                WGL_STENCIL_BITS_ARB, 8,
496                                WGL_SAMPLES_ARB, multisample,
497                                0
498                        };
499
500                        UINT nformats;
501            assert(__wglewChoosePixelFormatARB && "failed to get proc address for ChoosePixelFormatARB");
502            // ChoosePixelFormatARB proc address was obtained when setting up a dummy GL context in initialiseWGL()
503            // since glew hasn't been initialized yet, we have to cheat and use the previously obtained address
504                        if (!__wglewChoosePixelFormatARB(hdc, iattr, NULL, 1, &format, &nformats) || nformats <= 0)
505                return false;
506                }
507                else
508                {
509                        format = ChoosePixelFormat(hdc, &pfd);
510                }
511
512                return (format != 0 && SetPixelFormat(hdc, format, &pfd));
513        }
514
515        bool Win32GLSupport::supportsPBuffers()
516        {
517                return __WGLEW_ARB_pbuffer != GL_FALSE;
518        }
519    GLPBuffer *Win32GLSupport::createPBuffer(PixelComponentType format, size_t width, size_t height)
520        {
521                return new Win32PBuffer(format, width, height);
522        }
523}
Note: See TracBrowser for help on using the repository browser.