SFML logo
  • Main Page
  • Namespaces
  • Classes
  • Files
  • File List

ContextWGL.cpp

00001 
00002 //
00003 // SFML - Simple and Fast Multimedia Library
00004 // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
00005 //
00006 // This software is provided 'as-is', without any express or implied warranty.
00007 // In no event will the authors be held liable for any damages arising from the use of this software.
00008 //
00009 // Permission is granted to anyone to use this software for any purpose,
00010 // including commercial applications, and to alter it and redistribute it freely,
00011 // subject to the following restrictions:
00012 //
00013 // 1. The origin of this software must not be misrepresented;
00014 //    you must not claim that you wrote the original software.
00015 //    If you use this software in a product, an acknowledgment
00016 //    in the product documentation would be appreciated but is not required.
00017 //
00018 // 2. Altered source versions must be plainly marked as such,
00019 //    and must not be misrepresented as being the original software.
00020 //
00021 // 3. This notice may not be removed or altered from any source distribution.
00022 //
00024 
00026 // Headers
00028 #include <SFML/Window/Win32/ContextWGL.hpp>
00029 #include <SFML/Window/WindowImpl.hpp>
00030 #include <SFML/OpenGL.hpp>
00031 #include <SFML/Window/glext/wglext.h>
00032 #include <SFML/System/Lock.hpp>
00033 #include <SFML/System/Mutex.hpp>
00034 #include <SFML/System/Err.hpp>
00035 
00036 
00037 namespace sf
00038 {
00039 namespace priv
00040 {
00042 ContextWGL::ContextWGL(ContextWGL* shared) :
00043 myWindow       (NULL),
00044 myDeviceContext(NULL),
00045 myContext      (NULL),
00046 myOwnsWindow   (true)
00047 {
00048     // Creating a dummy window is mandatory: we could create a memory DC but then
00049     // its pixel format wouldn't match the regular contexts' format, and thus
00050     // wglShareLists would always fail. Too bad...
00051 
00052     // Create a dummy window (disabled and hidden)
00053     myWindow = CreateWindowA("STATIC", "", WS_POPUP | WS_DISABLED, 0, 0, 1, 1, NULL, NULL, GetModuleHandle(NULL), NULL);
00054     ShowWindow(myWindow, SW_HIDE);
00055     myDeviceContext = GetDC(myWindow);
00056 
00057     // Create the context
00058     if (myDeviceContext)
00059         CreateContext(shared, VideoMode::GetDesktopMode().BitsPerPixel, ContextSettings(0, 0, 0));
00060 
00061     // Activate the context
00062     SetActive(true);
00063 }
00064 
00065 
00067 ContextWGL::ContextWGL(ContextWGL* shared, const WindowImpl* owner, unsigned int bitsPerPixel, const ContextSettings& settings) :
00068 myWindow       (NULL),
00069 myDeviceContext(NULL),
00070 myContext      (NULL),
00071 myOwnsWindow   (false)
00072 {
00073     // Get the owner window and its device context
00074     myWindow = static_cast<HWND>(owner->GetHandle());
00075     myDeviceContext = GetDC(myWindow);
00076 
00077     // Create the context
00078     if (myDeviceContext)
00079         CreateContext(shared, bitsPerPixel, settings);
00080 
00081     // Activate the context
00082     SetActive(true);
00083 }
00084 
00085 
00087 ContextWGL::~ContextWGL()
00088 {
00089     // Destroy the OpenGL context
00090     if (myContext)
00091     {
00092         if (wglGetCurrentContext() == myContext)
00093             wglMakeCurrent(NULL, NULL);
00094         wglDeleteContext(myContext);
00095     }
00096 
00097     // Release the DC
00098     if (myWindow && myDeviceContext)
00099         ReleaseDC(myWindow, myDeviceContext);
00100 
00101     // Destroy the window if we own it
00102     if (myWindow && myOwnsWindow)
00103         DestroyWindow(myWindow);
00104 }
00105 
00106 
00108 bool ContextWGL::MakeCurrent()
00109 {
00110     if (myDeviceContext && myContext)
00111     {
00112         if (wglGetCurrentContext() != myContext)
00113             return wglMakeCurrent(myDeviceContext, myContext) != 0;
00114         else
00115             return true;
00116     }
00117     else
00118     {
00119         return false;
00120     }
00121 }
00122 
00123 
00125 void ContextWGL::Display()
00126 {
00127     if (myDeviceContext && myContext)
00128         SwapBuffers(myDeviceContext);
00129 }
00130 
00131 
00133 void ContextWGL::UseVerticalSync(bool enabled)
00134 {
00135     PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = reinterpret_cast<PFNWGLSWAPINTERVALEXTPROC>(wglGetProcAddress("wglSwapIntervalEXT"));
00136     if (wglSwapIntervalEXT)
00137         wglSwapIntervalEXT(enabled ? 1 : 0);
00138 }
00139 
00140 
00142 void ContextWGL::CreateContext(ContextWGL* shared, unsigned int bitsPerPixel, const ContextSettings& settings)
00143 {
00144     // Save the creation settings
00145     mySettings = settings;
00146 
00147     // Let's find a suitable pixel format -- first try with antialiasing
00148     int bestFormat = 0;
00149     if (mySettings.AntialiasingLevel > 0)
00150     {
00151         // Get the wglChoosePixelFormatARB function (it is an extension)
00152         PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = reinterpret_cast<PFNWGLCHOOSEPIXELFORMATARBPROC>(wglGetProcAddress("wglChoosePixelFormatARB"));
00153         if (wglChoosePixelFormatARB)
00154         {
00155             // Define the basic attributes we want for our window
00156             int intAttributes[] =
00157             {
00158                 WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
00159                 WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
00160                 WGL_ACCELERATION_ARB,   WGL_FULL_ACCELERATION_ARB,
00161                 WGL_DOUBLE_BUFFER_ARB,  GL_TRUE,
00162                 WGL_SAMPLE_BUFFERS_ARB, (mySettings.AntialiasingLevel ? GL_TRUE : GL_FALSE),
00163                 WGL_SAMPLES_ARB,        mySettings.AntialiasingLevel,
00164                 0,                      0
00165             };
00166 
00167             // Let's check how many formats are supporting our requirements
00168             int   formats[128];
00169             UINT  nbFormats;
00170             float floatAttributes[] = {0, 0};
00171             bool  isValid = wglChoosePixelFormatARB(myDeviceContext, intAttributes, floatAttributes, sizeof(formats) / sizeof(*formats), formats, &nbFormats) != 0;
00172             while ((!isValid || (nbFormats == 0)) && mySettings.AntialiasingLevel > 0)
00173             {
00174                 // Decrease the antialiasing level until we find a valid one
00175                 mySettings.AntialiasingLevel--;
00176                 intAttributes[11] = mySettings.AntialiasingLevel;
00177                 isValid = wglChoosePixelFormatARB(myDeviceContext, intAttributes, floatAttributes, sizeof(formats) / sizeof(*formats), formats, &nbFormats) != 0;
00178             }
00179 
00180             // Get the best format among the returned ones
00181             if (isValid && (nbFormats > 0))
00182             {
00183                 int bestScore = 0xFFFF;
00184                 for (UINT i = 0; i < nbFormats; ++i)
00185                 {
00186                     // Get the current format's attributes
00187                     PIXELFORMATDESCRIPTOR attributes;
00188                     attributes.nSize    = sizeof(attributes);
00189                     attributes.nVersion = 1;
00190                     DescribePixelFormat(myDeviceContext, formats[i], sizeof(attributes), &attributes);
00191 
00192                     // Evaluate the current configuration
00193                     int color = attributes.cRedBits + attributes.cGreenBits + attributes.cBlueBits + attributes.cAlphaBits;
00194                     int score = EvaluateFormat(bitsPerPixel, mySettings, color, attributes.cDepthBits, attributes.cStencilBits, mySettings.AntialiasingLevel);
00195 
00196                     // Keep it if it's better than the current best
00197                     if (score < bestScore)
00198                     {
00199                         bestScore  = score;
00200                         bestFormat = formats[i];
00201                     }
00202                 }
00203             }
00204         }
00205         else
00206         {
00207             // wglChoosePixelFormatARB not supported ; disabling antialiasing
00208             Err() << "Antialiasing is not supported ; it will be disabled" << std::endl;
00209             mySettings.AntialiasingLevel = 0;
00210         }
00211     }
00212 
00213     // Find a pixel format with no antialiasing, if not needed or not supported
00214     if (bestFormat == 0)
00215     {
00216         // Setup a pixel format descriptor from the rendering settings
00217         PIXELFORMATDESCRIPTOR descriptor;
00218         ZeroMemory(&descriptor, sizeof(descriptor));
00219         descriptor.nSize        = sizeof(descriptor);
00220         descriptor.nVersion     = 1;
00221         descriptor.iLayerType   = PFD_MAIN_PLANE;
00222         descriptor.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
00223         descriptor.iPixelType   = PFD_TYPE_RGBA;
00224         descriptor.cColorBits   = static_cast<BYTE>(bitsPerPixel);
00225         descriptor.cDepthBits   = static_cast<BYTE>(mySettings.DepthBits);
00226         descriptor.cStencilBits = static_cast<BYTE>(mySettings.StencilBits);
00227         descriptor.cAlphaBits   = bitsPerPixel == 32 ? 8 : 0;
00228 
00229         // Get the pixel format that best matches our requirements
00230         bestFormat = ChoosePixelFormat(myDeviceContext, &descriptor);
00231         if (bestFormat == 0)
00232         {
00233             Err() << "Failed to find a suitable pixel format for device context -- cannot create OpenGL context" << std::endl;
00234             return;
00235         }
00236     }
00237 
00238     // Extract the depth and stencil bits from the chosen format
00239     PIXELFORMATDESCRIPTOR actualFormat;
00240     actualFormat.nSize    = sizeof(actualFormat);
00241     actualFormat.nVersion = 1;
00242     DescribePixelFormat(myDeviceContext, bestFormat, sizeof(actualFormat), &actualFormat);
00243     mySettings.DepthBits   = actualFormat.cDepthBits;
00244     mySettings.StencilBits = actualFormat.cStencilBits;
00245 
00246     // Set the chosen pixel format
00247     if (!SetPixelFormat(myDeviceContext, bestFormat, &actualFormat))
00248     {
00249         Err() << "Failed to set pixel format for device context -- cannot create OpenGL context" << std::endl;
00250         return;
00251     }
00252 
00253     // Get the context to share display lists with
00254     HGLRC sharedContext = shared ? shared->myContext : NULL;
00255 
00256     // Create the OpenGL context -- first try an OpenGL 3.0 context if it is requested
00257     while (!myContext && (mySettings.MajorVersion >= 3))
00258     {
00259         PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = reinterpret_cast<PFNWGLCREATECONTEXTATTRIBSARBPROC>(wglGetProcAddress("wglCreateContextAttribsARB"));
00260         if (wglCreateContextAttribsARB)
00261         {
00262             int attributes[] =
00263             {
00264                 WGL_CONTEXT_MAJOR_VERSION_ARB, mySettings.MajorVersion,
00265                 WGL_CONTEXT_MINOR_VERSION_ARB, mySettings.MinorVersion,
00266                 0, 0
00267             };
00268             myContext = wglCreateContextAttribsARB(myDeviceContext, sharedContext, attributes);
00269         }
00270 
00271         // If we couldn't create an OpenGL 3 context, adjust the settings
00272         if (!myContext)
00273         {
00274             if (mySettings.MinorVersion > 0)
00275             {
00276                 // If the minor version is not 0, we decrease it and try again
00277                 mySettings.MinorVersion--;
00278             }
00279             else
00280             {
00281                 // If the minor version is 0, we decrease the major version and stop with 3.x contexts
00282                 mySettings.MajorVersion = 2;
00283             }
00284         }
00285     }
00286 
00287     // If the OpenGL 3.0 context failed or if we don't want one, create a regular OpenGL 1.x/2.x context
00288     if (!myContext)
00289     {
00290         myContext = wglCreateContext(myDeviceContext);
00291         if (!myContext)
00292         {
00293             Err() << "Failed to create an OpenGL context for this window" << std::endl;
00294             return;
00295         }
00296 
00297         // Share this context with others
00298         if (sharedContext)
00299         {
00300             // wglShareLists doesn't seem to be thread-safe
00301             static Mutex mutex;
00302             Lock lock(mutex);
00303 
00304             if (!wglShareLists(sharedContext, myContext))
00305                 Err() << "Failed to share the OpenGL context" << std::endl;
00306         }
00307     }
00308 }
00309 
00310 } // namespace priv
00311 
00312 } // namespace sf

 ::  Copyright © 2007-2008 Laurent Gomila, all rights reserved  ::  Documentation generated by doxygen 1.5.2  ::