src/video/win32/SDL_win32opengl.c
author Edgar Simo <bobbens@gmail.com>
Sun, 06 Jul 2008 17:06:37 +0000
branchgsoc2008_force_feedback
changeset 2498 ab567bd667bf
parent 2180 5ed37b16c1a7
child 2698 e1da92da346c
permissions -rw-r--r--
Fixed various mistakes in the doxygen.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_win32video.h"
    25 
    26 /* WGL implementation of SDL OpenGL support */
    27 
    28 #if SDL_VIDEO_OPENGL_WGL
    29 #include "SDL_opengl.h"
    30 
    31 #define DEFAULT_OPENGL "OPENGL32.DLL"
    32 
    33 
    34 int
    35 WIN_GL_LoadLibrary(_THIS, const char *path)
    36 {
    37     LPTSTR wpath;
    38     HANDLE handle;
    39 
    40     if (_this->gl_config.driver_loaded) {
    41         if (path) {
    42             SDL_SetError("OpenGL library already loaded");
    43             return -1;
    44         } else {
    45             ++_this->gl_config.driver_loaded;
    46             return 0;
    47         }
    48     }
    49     if (path == NULL) {
    50         path = SDL_getenv("SDL_OPENGL_LIBRARY");
    51     }
    52     if (path == NULL) {
    53         path = DEFAULT_OPENGL;
    54     }
    55     wpath = WIN_UTF8ToString(path);
    56     handle = LoadLibrary(wpath);
    57     SDL_free(wpath);
    58     if (!handle) {
    59         char message[1024];
    60         SDL_snprintf(message, SDL_arraysize(message), "LoadLibrary(\"%s\")",
    61                      path);
    62         WIN_SetError(message);
    63         return -1;
    64     }
    65 
    66     /* Load function pointers */
    67     _this->gl_data->wglGetProcAddress = (void *(WINAPI *) (const char *))
    68         GetProcAddress(handle, "wglGetProcAddress");
    69     _this->gl_data->wglCreateContext = (HGLRC(WINAPI *) (HDC))
    70         GetProcAddress(handle, "wglCreateContext");
    71     _this->gl_data->wglDeleteContext = (BOOL(WINAPI *) (HGLRC))
    72         GetProcAddress(handle, "wglDeleteContext");
    73     _this->gl_data->wglMakeCurrent = (BOOL(WINAPI *) (HDC, HGLRC))
    74         GetProcAddress(handle, "wglMakeCurrent");
    75     _this->gl_data->wglSwapIntervalEXT = (void (WINAPI *) (int))
    76         GetProcAddress(handle, "wglSwapIntervalEXT");
    77     _this->gl_data->wglGetSwapIntervalEXT = (int (WINAPI *) (void))
    78         GetProcAddress(handle, "wglGetSwapIntervalEXT");
    79 
    80     if (!_this->gl_data->wglGetProcAddress ||
    81         !_this->gl_data->wglCreateContext ||
    82         !_this->gl_data->wglDeleteContext ||
    83         !_this->gl_data->wglMakeCurrent) {
    84         SDL_SetError("Could not retrieve OpenGL functions");
    85         FreeLibrary(handle);
    86         return -1;
    87     }
    88 
    89     _this->gl_config.dll_handle = handle;
    90     SDL_strlcpy(_this->gl_config.driver_path, path,
    91                 SDL_arraysize(_this->gl_config.driver_path));
    92     _this->gl_config.driver_loaded = 1;
    93     return 0;
    94 }
    95 
    96 void *
    97 WIN_GL_GetProcAddress(_THIS, const char *proc)
    98 {
    99     void *func;
   100 
   101     /* This is to pick up extensions */
   102     func = _this->gl_data->wglGetProcAddress(proc);
   103     if (!func) {
   104         /* This is probably a normal GL function */
   105         func = GetProcAddress(_this->gl_config.dll_handle, proc);
   106     }
   107     return func;
   108 }
   109 
   110 static void
   111 WIN_GL_UnloadLibrary(_THIS)
   112 {
   113     if (_this->gl_config.driver_loaded > 0) {
   114         if (--_this->gl_config.driver_loaded > 0) {
   115             return;
   116         }
   117         FreeLibrary((HMODULE) _this->gl_config.dll_handle);
   118         _this->gl_config.dll_handle = NULL;
   119     }
   120 }
   121 
   122 static void
   123 WIN_GL_SetupPixelFormat(_THIS, PIXELFORMATDESCRIPTOR * pfd)
   124 {
   125     SDL_zerop(pfd);
   126     pfd->nSize = sizeof(*pfd);
   127     pfd->nVersion = 1;
   128     pfd->dwFlags = (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL);
   129     if (_this->gl_config.double_buffer) {
   130         pfd->dwFlags |= PFD_DOUBLEBUFFER;
   131     }
   132     if (_this->gl_config.stereo) {
   133         pfd->dwFlags |= PFD_STEREO;
   134     }
   135     pfd->iLayerType = PFD_MAIN_PLANE;
   136     pfd->iPixelType = PFD_TYPE_RGBA;
   137     pfd->cRedBits = _this->gl_config.red_size;
   138     pfd->cGreenBits = _this->gl_config.green_size;
   139     pfd->cBlueBits = _this->gl_config.blue_size;
   140     pfd->cAlphaBits = _this->gl_config.alpha_size;
   141     if (_this->gl_config.buffer_size) {
   142         pfd->cColorBits =
   143             _this->gl_config.buffer_size - _this->gl_config.alpha_size;
   144     } else {
   145         pfd->cColorBits = (pfd->cRedBits + pfd->cGreenBits + pfd->cBlueBits);
   146     }
   147     pfd->cAccumRedBits = _this->gl_config.accum_red_size;
   148     pfd->cAccumGreenBits = _this->gl_config.accum_green_size;
   149     pfd->cAccumBlueBits = _this->gl_config.accum_blue_size;
   150     pfd->cAccumAlphaBits = _this->gl_config.accum_alpha_size;
   151     pfd->cAccumBits =
   152         (pfd->cAccumRedBits + pfd->cAccumGreenBits + pfd->cAccumBlueBits +
   153          pfd->cAccumAlphaBits);
   154     pfd->cDepthBits = _this->gl_config.depth_size;
   155     pfd->cStencilBits = _this->gl_config.stencil_size;
   156 }
   157 
   158 /* Choose the closest pixel format that meets or exceeds the target.
   159    FIXME: Should we weight any particular attribute over any other?
   160 */
   161 static int
   162 WIN_GL_ChoosePixelFormat(HDC hdc, PIXELFORMATDESCRIPTOR * target)
   163 {
   164     PIXELFORMATDESCRIPTOR pfd;
   165     int count, index, best = 0;
   166     unsigned int dist, best_dist = ~0U;
   167 
   168     count = DescribePixelFormat(hdc, 1, sizeof(pfd), NULL);
   169 
   170     for (index = 1; index <= count; index++) {
   171 
   172         if (!DescribePixelFormat(hdc, index, sizeof(pfd), &pfd)) {
   173             continue;
   174         }
   175 
   176         if ((pfd.dwFlags & target->dwFlags) != target->dwFlags) {
   177             continue;
   178         }
   179 
   180         if (pfd.iLayerType != target->iLayerType) {
   181             continue;
   182         }
   183         if (pfd.iPixelType != target->iPixelType) {
   184             continue;
   185         }
   186 
   187         dist = 0;
   188 
   189         if (pfd.cColorBits < target->cColorBits) {
   190             continue;
   191         } else {
   192             dist += (pfd.cColorBits - target->cColorBits);
   193         }
   194         if (pfd.cRedBits < target->cRedBits) {
   195             continue;
   196         } else {
   197             dist += (pfd.cRedBits - target->cRedBits);
   198         }
   199         if (pfd.cGreenBits < target->cGreenBits) {
   200             continue;
   201         } else {
   202             dist += (pfd.cGreenBits - target->cGreenBits);
   203         }
   204         if (pfd.cBlueBits < target->cBlueBits) {
   205             continue;
   206         } else {
   207             dist += (pfd.cBlueBits - target->cBlueBits);
   208         }
   209         if (pfd.cAlphaBits < target->cAlphaBits) {
   210             continue;
   211         } else {
   212             dist += (pfd.cAlphaBits - target->cAlphaBits);
   213         }
   214         if (pfd.cAccumBits < target->cAccumBits) {
   215             continue;
   216         } else {
   217             dist += (pfd.cAccumBits - target->cAccumBits);
   218         }
   219         if (pfd.cAccumRedBits < target->cAccumRedBits) {
   220             continue;
   221         } else {
   222             dist += (pfd.cAccumRedBits - target->cAccumRedBits);
   223         }
   224         if (pfd.cAccumGreenBits < target->cAccumGreenBits) {
   225             continue;
   226         } else {
   227             dist += (pfd.cAccumGreenBits - target->cAccumGreenBits);
   228         }
   229         if (pfd.cAccumBlueBits < target->cAccumBlueBits) {
   230             continue;
   231         } else {
   232             dist += (pfd.cAccumBlueBits - target->cAccumBlueBits);
   233         }
   234         if (pfd.cAccumAlphaBits < target->cAccumAlphaBits) {
   235             continue;
   236         } else {
   237             dist += (pfd.cAccumAlphaBits - target->cAccumAlphaBits);
   238         }
   239         if (pfd.cDepthBits < target->cDepthBits) {
   240             continue;
   241         } else {
   242             dist += (pfd.cDepthBits - target->cDepthBits);
   243         }
   244         if (pfd.cStencilBits < target->cStencilBits) {
   245             continue;
   246         } else {
   247             dist += (pfd.cStencilBits - target->cStencilBits);
   248         }
   249 
   250         if (dist < best_dist) {
   251             best = index;
   252             best_dist = dist;
   253         }
   254     }
   255 
   256     return best;
   257 }
   258 
   259 static SDL_bool
   260 HasExtension(const char *extension, const char *extensions)
   261 {
   262     const char *start;
   263     const char *where, *terminator;
   264 
   265     /* Extension names should not have spaces. */
   266     where = SDL_strchr(extension, ' ');
   267     if (where || *extension == '\0')
   268         return SDL_FALSE;
   269 
   270     if (!extensions)
   271         return SDL_FALSE;
   272 
   273     /* It takes a bit of care to be fool-proof about parsing the
   274      * OpenGL extensions string. Don't be fooled by sub-strings,
   275      * etc. */
   276 
   277     start = extensions;
   278 
   279     for (;;) {
   280         where = SDL_strstr(start, extension);
   281         if (!where)
   282             break;
   283 
   284         terminator = where + SDL_strlen(extension);
   285         if (where == start || *(where - 1) == ' ')
   286             if (*terminator == ' ' || *terminator == '\0')
   287                 return SDL_TRUE;
   288 
   289         start = terminator;
   290     }
   291     return SDL_FALSE;
   292 }
   293 
   294 static void
   295 WIN_GL_InitExtensions(_THIS, HDC hdc)
   296 {
   297     const char *(WINAPI * wglGetExtensionsStringARB) (HDC) = 0;
   298     const char *extensions;
   299 
   300     wglGetExtensionsStringARB = (const char *(WINAPI *) (HDC))
   301         _this->gl_data->wglGetProcAddress("wglGetExtensionsStringARB");
   302     if (wglGetExtensionsStringARB) {
   303         extensions = wglGetExtensionsStringARB(hdc);
   304     } else {
   305         extensions = NULL;
   306     }
   307 
   308     /* Check for WGL_ARB_pixel_format */
   309     _this->gl_data->WGL_ARB_pixel_format = 0;
   310     if (HasExtension("WGL_ARB_pixel_format", extensions)) {
   311         _this->gl_data->wglChoosePixelFormatARB = (BOOL(WINAPI *)
   312                                                    (HDC, const int *,
   313                                                     const FLOAT *, UINT,
   314                                                     int *, UINT *))
   315             WIN_GL_GetProcAddress(_this, "wglChoosePixelFormatARB");
   316         _this->gl_data->wglGetPixelFormatAttribivARB =
   317             (BOOL(WINAPI *) (HDC, int, int, UINT, const int *, int *))
   318             WIN_GL_GetProcAddress(_this, "wglGetPixelFormatAttribivARB");
   319 
   320         if ((_this->gl_data->wglChoosePixelFormatARB != NULL) &&
   321             (_this->gl_data->wglGetPixelFormatAttribivARB != NULL)) {
   322             _this->gl_data->WGL_ARB_pixel_format = 1;
   323         }
   324     }
   325 
   326     /* Check for WGL_EXT_swap_control */
   327     if (HasExtension("WGL_EXT_swap_control", extensions)) {
   328         _this->gl_data->wglSwapIntervalEXT =
   329             WIN_GL_GetProcAddress(_this, "wglSwapIntervalEXT");
   330         _this->gl_data->wglGetSwapIntervalEXT =
   331             WIN_GL_GetProcAddress(_this, "wglGetSwapIntervalEXT");
   332     } else {
   333         _this->gl_data->wglSwapIntervalEXT = NULL;
   334         _this->gl_data->wglGetSwapIntervalEXT = NULL;
   335     }
   336 }
   337 
   338 static int
   339 WIN_GL_ChoosePixelFormatARB(_THIS, int *iAttribs, float *fAttribs)
   340 {
   341     HWND hwnd;
   342     HDC hdc;
   343     PIXELFORMATDESCRIPTOR pfd;
   344     HGLRC hglrc;
   345     int pixel_format = 0;
   346     unsigned int matching;
   347 
   348     hwnd =
   349         CreateWindow(SDL_Appname, SDL_Appname, (WS_POPUP | WS_DISABLED), 0, 0,
   350                      10, 10, NULL, NULL, SDL_Instance, NULL);
   351     WIN_PumpEvents(_this);
   352 
   353     hdc = GetDC(hwnd);
   354 
   355     WIN_GL_SetupPixelFormat(_this, &pfd);
   356 
   357     SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd);
   358 
   359     hglrc = _this->gl_data->wglCreateContext(hdc);
   360     if (hglrc) {
   361         _this->gl_data->wglMakeCurrent(hdc, hglrc);
   362 
   363         WIN_GL_InitExtensions(_this, hdc);
   364 
   365         if (_this->gl_data->WGL_ARB_pixel_format) {
   366             _this->gl_data->wglChoosePixelFormatARB(hdc, iAttribs, fAttribs,
   367                                                     1, &pixel_format,
   368                                                     &matching);
   369         }
   370 
   371         _this->gl_data->wglMakeCurrent(NULL, NULL);
   372         _this->gl_data->wglDeleteContext(hglrc);
   373     }
   374     ReleaseDC(hwnd, hdc);
   375     DestroyWindow(hwnd);
   376     WIN_PumpEvents(_this);
   377 
   378     return pixel_format;
   379 }
   380 
   381 static int
   382 WIN_GL_Initialize(_THIS)
   383 {
   384     if (_this->gl_data) {
   385         ++_this->gl_data->initialized;
   386         return 0;
   387     }
   388 
   389     _this->gl_data =
   390         (struct SDL_GLDriverData *) SDL_calloc(1,
   391                                                sizeof(struct
   392                                                       SDL_GLDriverData));
   393     if (!_this->gl_data) {
   394         SDL_OutOfMemory();
   395         return -1;
   396     }
   397     _this->gl_data->initialized = 1;
   398 
   399     if (WIN_GL_LoadLibrary(_this, NULL) < 0) {
   400         return -1;
   401     }
   402 
   403     return 0;
   404 }
   405 
   406 static void
   407 WIN_GL_Shutdown(_THIS)
   408 {
   409     if (!_this->gl_data || (--_this->gl_data->initialized > 0)) {
   410         return;
   411     }
   412 
   413     WIN_GL_UnloadLibrary(_this);
   414 
   415     SDL_free(_this->gl_data);
   416     _this->gl_data = NULL;
   417 }
   418 
   419 int
   420 WIN_GL_SetupWindow(_THIS, SDL_Window * window)
   421 {
   422     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   423     PIXELFORMATDESCRIPTOR pfd;
   424     int pixel_format;
   425     int iAttribs[64];
   426     int *iAttr;
   427     float fAttribs[1] = { 0 };
   428 
   429     if (WIN_GL_Initialize(_this) < 0) {
   430         return -1;
   431     }
   432 
   433     WIN_GL_SetupPixelFormat(_this, &pfd);
   434 
   435     /* setup WGL_ARB_pixel_format attribs */
   436     iAttr = &iAttribs[0];
   437 
   438     *iAttr++ = WGL_DRAW_TO_WINDOW_ARB;
   439     *iAttr++ = GL_TRUE;
   440     *iAttr++ = WGL_ACCELERATION_ARB;
   441     *iAttr++ = WGL_FULL_ACCELERATION_ARB;
   442     *iAttr++ = WGL_RED_BITS_ARB;
   443     *iAttr++ = _this->gl_config.red_size;
   444     *iAttr++ = WGL_GREEN_BITS_ARB;
   445     *iAttr++ = _this->gl_config.green_size;
   446     *iAttr++ = WGL_BLUE_BITS_ARB;
   447     *iAttr++ = _this->gl_config.blue_size;
   448 
   449     if (_this->gl_config.alpha_size) {
   450         *iAttr++ = WGL_ALPHA_BITS_ARB;
   451         *iAttr++ = _this->gl_config.alpha_size;
   452     }
   453 
   454     *iAttr++ = WGL_DOUBLE_BUFFER_ARB;
   455     *iAttr++ = _this->gl_config.double_buffer;
   456 
   457     *iAttr++ = WGL_DEPTH_BITS_ARB;
   458     *iAttr++ = _this->gl_config.depth_size;
   459 
   460     if (_this->gl_config.stencil_size) {
   461         *iAttr++ = WGL_STENCIL_BITS_ARB;
   462         *iAttr++ = _this->gl_config.stencil_size;
   463     }
   464 
   465     if (_this->gl_config.accum_red_size) {
   466         *iAttr++ = WGL_ACCUM_RED_BITS_ARB;
   467         *iAttr++ = _this->gl_config.accum_red_size;
   468     }
   469 
   470     if (_this->gl_config.accum_green_size) {
   471         *iAttr++ = WGL_ACCUM_GREEN_BITS_ARB;
   472         *iAttr++ = _this->gl_config.accum_green_size;
   473     }
   474 
   475     if (_this->gl_config.accum_blue_size) {
   476         *iAttr++ = WGL_ACCUM_BLUE_BITS_ARB;
   477         *iAttr++ = _this->gl_config.accum_blue_size;
   478     }
   479 
   480     if (_this->gl_config.accum_alpha_size) {
   481         *iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB;
   482         *iAttr++ = _this->gl_config.accum_alpha_size;
   483     }
   484 
   485     if (_this->gl_config.stereo) {
   486         *iAttr++ = WGL_STEREO_ARB;
   487         *iAttr++ = GL_TRUE;
   488     }
   489 
   490     if (_this->gl_config.multisamplebuffers) {
   491         *iAttr++ = WGL_SAMPLE_BUFFERS_ARB;
   492         *iAttr++ = _this->gl_config.multisamplebuffers;
   493     }
   494 
   495     if (_this->gl_config.multisamplesamples) {
   496         *iAttr++ = WGL_SAMPLES_ARB;
   497         *iAttr++ = _this->gl_config.multisamplesamples;
   498     }
   499 
   500     if (_this->gl_config.accelerated >= 0) {
   501         *iAttr++ = WGL_ACCELERATION_ARB;
   502         *iAttr++ =
   503             (_this->gl_config.
   504              accelerated ? WGL_GENERIC_ACCELERATION_ARB :
   505              WGL_NO_ACCELERATION_ARB);
   506     }
   507 
   508     *iAttr = 0;
   509 
   510     /* Choose and set the closest available pixel format */
   511     pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs);
   512     if (!pixel_format) {
   513         pixel_format = WIN_GL_ChoosePixelFormat(hdc, &pfd);
   514     }
   515     if (!pixel_format) {
   516         SDL_SetError("No matching GL pixel format available");
   517         return -1;
   518     }
   519     if (!SetPixelFormat(hdc, pixel_format, &pfd)) {
   520         WIN_SetError("SetPixelFormat()");
   521         return (-1);
   522     }
   523     return 0;
   524 }
   525 
   526 void
   527 WIN_GL_CleanupWindow(_THIS, SDL_Window * window)
   528 {
   529     WIN_GL_Shutdown(_this);
   530 }
   531 
   532 SDL_GLContext
   533 WIN_GL_CreateContext(_THIS, SDL_Window * window)
   534 {
   535     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   536     HGLRC context;
   537 
   538     context = _this->gl_data->wglCreateContext(hdc);
   539     if (!context) {
   540         SDL_SetError("Could not create GL context");
   541         return NULL;
   542     }
   543 
   544     if (WIN_GL_MakeCurrent(_this, window, context) < 0) {
   545         WIN_GL_DeleteContext(_this, context);
   546         return NULL;
   547     }
   548 
   549     WIN_GL_InitExtensions(_this, hdc);
   550 
   551     return context;
   552 }
   553 
   554 int
   555 WIN_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   556 {
   557     HDC hdc;
   558     int status;
   559 
   560     if (window) {
   561         hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   562     } else {
   563         hdc = NULL;
   564     }
   565     if (!_this->gl_data->wglMakeCurrent(hdc, (HGLRC) context)) {
   566         WIN_SetError("wglMakeCurrent()");
   567         status = -1;
   568     } else {
   569         status = 0;
   570     }
   571     return status;
   572 }
   573 
   574 int
   575 WIN_GL_SetSwapInterval(_THIS, int interval)
   576 {
   577     if (_this->gl_data->wglSwapIntervalEXT) {
   578         _this->gl_data->wglSwapIntervalEXT(interval);
   579         return 0;
   580     } else {
   581         SDL_Unsupported();
   582         return -1;
   583     }
   584 }
   585 
   586 int
   587 WIN_GL_GetSwapInterval(_THIS)
   588 {
   589     if (_this->gl_data->wglGetSwapIntervalEXT) {
   590         return _this->gl_data->wglGetSwapIntervalEXT();
   591     } else {
   592         SDL_Unsupported();
   593         return -1;
   594     }
   595 }
   596 
   597 void
   598 WIN_GL_SwapWindow(_THIS, SDL_Window * window)
   599 {
   600     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   601 
   602     SwapBuffers(hdc);
   603 }
   604 
   605 void
   606 WIN_GL_DeleteContext(_THIS, SDL_GLContext context)
   607 {
   608     _this->gl_data->wglDeleteContext((HGLRC) context);
   609 }
   610 
   611 #endif /* SDL_VIDEO_OPENGL_WGL */
   612 
   613 /* vi: set ts=4 sw=4 expandtab: */