2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
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.
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.
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
22 #include "SDL_config.h"
24 /* WGL implementation of SDL OpenGL support */
27 #include "SDL_opengl.h"
29 #include "SDL_lowvideo.h"
30 #include "SDL_wingl_c.h"
33 #define DEFAULT_GL_DRIVER_PATH "OPENGL32.DLL"
36 /* If setting the HDC fails, we may need to recreate the window (MSDN) */
37 static int WIN_GL_ResetWindow(_THIS)
41 #ifndef _WIN32_WCE /* FIXME WinCE needs the UNICODE version of CreateWindow() */
42 /* This doesn't work with DirectX code (see CVS comments) */
43 /* If we were passed a window, then we can't create a new one */
44 if ( !SDL_windowid && SDL_strcmp(this->name, "windib") == 0 ) {
45 /* Save the existing window attributes */
47 RECT rect = { 0, 0, 0, 0 };
48 style = GetWindowLong(SDL_Window, GWL_STYLE);
49 GetWindowRect(SDL_Window, &rect);
50 DestroyWindow(SDL_Window);
51 WIN_FlushMessageQueue();
54 SDL_Window = CreateWindow(SDL_Appname, SDL_Appname,
57 (rect.right-rect.left)+1,
58 (rect.bottom-rect.top)+1,
59 NULL, NULL, SDL_Instance, NULL);
60 WIN_FlushMessageQueue();
64 this->SetCaption(this, this->wm_title, this->wm_icon);
66 SDL_SetError("Couldn't create window");
70 #endif /* !_WIN32_WCE */
72 SDL_SetError("Unable to reset window for OpenGL context");
80 static int ExtensionSupported(const char *extension, const char *extensions)
83 const char *where, *terminator;
85 /* Extension names should not have spaces. */
86 where = SDL_strchr(extension, ' ');
87 if ( where || *extension == '\0' )
93 /* It takes a bit of care to be fool-proof about parsing the
94 * OpenGL extensions string. Don't be fooled by sub-strings,
101 where = SDL_strstr(start, extension);
104 terminator = where + SDL_strlen(extension);
105 if (where == start || *(where - 1) == ' ')
106 if (*terminator == ' ' || *terminator == '\0') return 1;
114 static int ChoosePixelFormatARB(_THIS, const int *iAttribs, const FLOAT *fAttribs)
119 const char * (WINAPI *wglGetExtensionsStringARB)(HDC) = 0;
120 const char *extensions;
124 hwnd = CreateWindow(SDL_Appname, SDL_Appname, WS_POPUP | WS_DISABLED,
126 NULL, NULL, SDL_Instance, NULL);
127 WIN_FlushMessageQueue();
131 SetPixelFormat(hdc, ChoosePixelFormat(hdc, &GL_pfd), &GL_pfd);
133 hglrc = this->gl_data->wglCreateContext(hdc);
135 this->gl_data->wglMakeCurrent(hdc, hglrc);
138 wglGetExtensionsStringARB = (const char * (WINAPI *)(HDC))
139 this->gl_data->wglGetProcAddress("wglGetExtensionsStringARB");
141 if( wglGetExtensionsStringARB ) {
142 extensions = wglGetExtensionsStringARB(hdc);
147 this->gl_data->WGL_ARB_pixel_format = 0;
148 if( ExtensionSupported("WGL_ARB_pixel_format", extensions) ) {
149 BOOL (WINAPI *wglChoosePixelFormatARB)(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
150 wglChoosePixelFormatARB =
151 (BOOL (WINAPI *)(HDC, const int *, const FLOAT *, UINT, int *, UINT *))
152 this->gl_data->wglGetProcAddress("wglChoosePixelFormatARB");
153 if( wglChoosePixelFormatARB &&
154 wglChoosePixelFormatARB(hdc, iAttribs, fAttribs, 1, &pformat, &matches) && pformat ) {
155 this->gl_data->WGL_ARB_pixel_format = 1;
160 this->gl_data->wglMakeCurrent(NULL, NULL);
161 this->gl_data->wglDeleteContext(hglrc);
163 ReleaseDC(hwnd, hdc);
165 WIN_FlushMessageQueue();
170 #endif /* SDL_VIDEO_OPENGL */
172 int WIN_GL_SetupWindow(_THIS)
179 int *iAccelAttr = NULL;
180 float fAttribs[1] = { 0 };
181 const GLubyte *(WINAPI *glGetStringFunc)(GLenum);
184 /* load the gl driver from a default path */
185 if ( ! this->gl_config.driver_loaded ) {
186 /* no driver has been loaded, use default (ourselves) */
187 if ( WIN_GL_LoadLibrary(this, NULL) < 0 ) {
192 /* Set up the pixel format descriptor with our needed format */
193 SDL_memset(&GL_pfd, 0, sizeof(GL_pfd));
194 GL_pfd.nSize = sizeof(GL_pfd);
196 GL_pfd.dwFlags = (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL);
197 if ( this->gl_config.double_buffer ) {
198 GL_pfd.dwFlags |= PFD_DOUBLEBUFFER;
200 if ( this->gl_config.stereo ) {
201 GL_pfd.dwFlags |= PFD_STEREO;
203 GL_pfd.iPixelType = PFD_TYPE_RGBA;
204 GL_pfd.cColorBits = this->gl_config.buffer_size;
205 GL_pfd.cRedBits = this->gl_config.red_size;
206 GL_pfd.cGreenBits = this->gl_config.green_size;
207 GL_pfd.cBlueBits = this->gl_config.blue_size;
208 GL_pfd.cAlphaBits = this->gl_config.alpha_size;
209 GL_pfd.cAccumRedBits = this->gl_config.accum_red_size;
210 GL_pfd.cAccumGreenBits = this->gl_config.accum_green_size;
211 GL_pfd.cAccumBlueBits = this->gl_config.accum_blue_size;
212 GL_pfd.cAccumAlphaBits = this->gl_config.accum_alpha_size;
214 (GL_pfd.cAccumRedBits + GL_pfd.cAccumGreenBits +
215 GL_pfd.cAccumBlueBits + GL_pfd.cAccumAlphaBits);
216 GL_pfd.cDepthBits = this->gl_config.depth_size;
217 GL_pfd.cStencilBits = this->gl_config.stencil_size;
219 /* setup WGL_ARB_pixel_format attribs */
220 iAttr = &iAttribs[0];
222 *iAttr++ = WGL_DRAW_TO_WINDOW_ARB;
224 *iAttr++ = WGL_RED_BITS_ARB;
225 *iAttr++ = this->gl_config.red_size;
226 *iAttr++ = WGL_GREEN_BITS_ARB;
227 *iAttr++ = this->gl_config.green_size;
228 *iAttr++ = WGL_BLUE_BITS_ARB;
229 *iAttr++ = this->gl_config.blue_size;
231 /* We always choose either FULL or NO accel on Windows, because of flaky
232 drivers. If the app didn't specify, we use FULL, because that's
233 probably what they wanted (and if you didn't care and got FULL, that's
234 a perfectly valid result in any case. */
235 *iAttr++ = WGL_ACCELERATION_ARB;
237 if (this->gl_config.accelerated) {
238 *iAttr++ = WGL_FULL_ACCELERATION_ARB;
240 *iAttr++ = WGL_NO_ACCELERATION_ARB;
243 if ( this->gl_config.alpha_size ) {
244 *iAttr++ = WGL_ALPHA_BITS_ARB;
245 *iAttr++ = this->gl_config.alpha_size;
248 *iAttr++ = WGL_DOUBLE_BUFFER_ARB;
249 *iAttr++ = this->gl_config.double_buffer;
251 *iAttr++ = WGL_DEPTH_BITS_ARB;
252 *iAttr++ = this->gl_config.depth_size;
254 if ( this->gl_config.stencil_size ) {
255 *iAttr++ = WGL_STENCIL_BITS_ARB;
256 *iAttr++ = this->gl_config.stencil_size;
259 if ( this->gl_config.accum_red_size ) {
260 *iAttr++ = WGL_ACCUM_RED_BITS_ARB;
261 *iAttr++ = this->gl_config.accum_red_size;
264 if ( this->gl_config.accum_green_size ) {
265 *iAttr++ = WGL_ACCUM_GREEN_BITS_ARB;
266 *iAttr++ = this->gl_config.accum_green_size;
269 if ( this->gl_config.accum_blue_size ) {
270 *iAttr++ = WGL_ACCUM_BLUE_BITS_ARB;
271 *iAttr++ = this->gl_config.accum_blue_size;
274 if ( this->gl_config.accum_alpha_size ) {
275 *iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB;
276 *iAttr++ = this->gl_config.accum_alpha_size;
279 if ( this->gl_config.stereo ) {
280 *iAttr++ = WGL_STEREO_ARB;
284 if ( this->gl_config.multisamplebuffers ) {
285 *iAttr++ = WGL_SAMPLE_BUFFERS_ARB;
286 *iAttr++ = this->gl_config.multisamplebuffers;
289 if ( this->gl_config.multisamplesamples ) {
290 *iAttr++ = WGL_SAMPLES_ARB;
291 *iAttr++ = this->gl_config.multisamplesamples;
297 /* Get the window device context for our OpenGL drawing */
298 GL_hdc = GetDC(SDL_Window);
299 if ( GL_hdc == NULL ) {
300 SDL_SetError("Unable to get DC for SDL_Window");
304 /* Choose and set the closest available pixel format */
305 pixel_format = ChoosePixelFormatARB(this, iAttribs, fAttribs);
306 /* App said "don't care about accel" and FULL accel failed. Try NO. */
307 if ( ( !pixel_format ) && ( this->gl_config.accelerated < 0 ) ) {
308 *iAccelAttr = WGL_NO_ACCELERATION_ARB;
309 pixel_format = ChoosePixelFormatARB(this, iAttribs, fAttribs);
310 *iAccelAttr = WGL_FULL_ACCELERATION_ARB; /* if we try again. */
312 if ( !pixel_format ) {
313 pixel_format = ChoosePixelFormat(GL_hdc, &GL_pfd);
315 if ( !pixel_format ) {
316 SDL_SetError("No matching GL pixel format available");
319 if ( !SetPixelFormat(GL_hdc, pixel_format, &GL_pfd) ) {
321 /* First time through, try resetting the window */
322 if ( WIN_GL_ResetWindow(this) < 0 ) {
327 SDL_SetError("Unable to set HDC pixel format");
330 /* We either succeeded or failed by this point */
333 DescribePixelFormat(GL_hdc, pixel_format, sizeof(GL_pfd), &GL_pfd);
335 GL_hrc = this->gl_data->wglCreateContext(GL_hdc);
336 if ( GL_hrc == NULL ) {
337 SDL_SetError("Unable to create GL context");
340 if ( WIN_GL_MakeCurrent(this) < 0 ) {
345 /* Get the wglGetPixelFormatAttribivARB pointer for the context */
346 if ( this->gl_data->WGL_ARB_pixel_format ) {
347 this->gl_data->wglGetPixelFormatAttribivARB =
348 (BOOL (WINAPI *)(HDC, int, int, UINT, const int *, int *))
349 this->gl_data->wglGetProcAddress("wglGetPixelFormatAttribivARB");
351 this->gl_data->wglGetPixelFormatAttribivARB = NULL;
354 /* Vsync control under Windows. Checking glGetString here is
355 * somewhat a documented and reliable hack - it was originally
356 * as a feature added by mistake, but since so many people rely
357 * on it, it will not be removed. strstr should be safe here.*/
358 glGetStringFunc = WIN_GL_GetProcAddress(this, "glGetString");
359 if ( glGetStringFunc ) {
360 wglext = (const char *)glGetStringFunc(GL_EXTENSIONS);
362 /* Uh oh, something is seriously wrong here... */
365 if ( wglext && SDL_strstr(wglext, "WGL_EXT_swap_control") ) {
366 this->gl_data->wglSwapIntervalEXT = WIN_GL_GetProcAddress(this, "wglSwapIntervalEXT");
367 this->gl_data->wglGetSwapIntervalEXT = WIN_GL_GetProcAddress(this, "wglGetSwapIntervalEXT");
369 this->gl_data->wglSwapIntervalEXT = NULL;
370 this->gl_data->wglGetSwapIntervalEXT = NULL;
372 if ( this->gl_config.swap_control >= 0 ) {
373 if ( this->gl_data->wglSwapIntervalEXT ) {
374 this->gl_data->wglSwapIntervalEXT(this->gl_config.swap_control);
378 SDL_SetError("WIN driver not configured with OpenGL");
388 void WIN_GL_ShutDown(_THIS)
391 /* Clean up OpenGL */
393 this->gl_data->wglMakeCurrent(NULL, NULL);
394 this->gl_data->wglDeleteContext(GL_hrc);
398 ReleaseDC(SDL_Window, GL_hdc);
403 WIN_GL_UnloadLibrary(this);
404 #endif /* SDL_VIDEO_OPENGL */
409 /* Make the current context active */
410 int WIN_GL_MakeCurrent(_THIS)
415 if ( ! this->gl_data->wglMakeCurrent(GL_hdc, GL_hrc) ) {
416 SDL_SetError("Unable to make GL context current");
422 /* Get attribute data from wgl. */
423 int WIN_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value)
427 if (attrib == SDL_GL_SWAP_CONTROL) {
428 if ( this->gl_data->wglGetSwapIntervalEXT ) {
429 *value = this->gl_data->wglGetSwapIntervalEXT();
435 if ( this->gl_data->wglGetPixelFormatAttribivARB ) {
439 case SDL_GL_RED_SIZE:
440 wgl_attrib = WGL_RED_BITS_ARB;
442 case SDL_GL_GREEN_SIZE:
443 wgl_attrib = WGL_GREEN_BITS_ARB;
445 case SDL_GL_BLUE_SIZE:
446 wgl_attrib = WGL_BLUE_BITS_ARB;
448 case SDL_GL_ALPHA_SIZE:
449 wgl_attrib = WGL_ALPHA_BITS_ARB;
451 case SDL_GL_DOUBLEBUFFER:
452 wgl_attrib = WGL_DOUBLE_BUFFER_ARB;
454 case SDL_GL_BUFFER_SIZE:
455 wgl_attrib = WGL_COLOR_BITS_ARB;
457 case SDL_GL_DEPTH_SIZE:
458 wgl_attrib = WGL_DEPTH_BITS_ARB;
460 case SDL_GL_STENCIL_SIZE:
461 wgl_attrib = WGL_STENCIL_BITS_ARB;
463 case SDL_GL_ACCUM_RED_SIZE:
464 wgl_attrib = WGL_ACCUM_RED_BITS_ARB;
466 case SDL_GL_ACCUM_GREEN_SIZE:
467 wgl_attrib = WGL_ACCUM_GREEN_BITS_ARB;
469 case SDL_GL_ACCUM_BLUE_SIZE:
470 wgl_attrib = WGL_ACCUM_BLUE_BITS_ARB;
472 case SDL_GL_ACCUM_ALPHA_SIZE:
473 wgl_attrib = WGL_ACCUM_ALPHA_BITS_ARB;
476 wgl_attrib = WGL_STEREO_ARB;
478 case SDL_GL_MULTISAMPLEBUFFERS:
479 wgl_attrib = WGL_SAMPLE_BUFFERS_ARB;
481 case SDL_GL_MULTISAMPLESAMPLES:
482 wgl_attrib = WGL_SAMPLES_ARB;
484 case SDL_GL_ACCELERATED_VISUAL:
485 wgl_attrib = WGL_ACCELERATION_ARB;
486 this->gl_data->wglGetPixelFormatAttribivARB(GL_hdc, pixel_format, 0, 1, &wgl_attrib, value);
487 if ( *value == WGL_NO_ACCELERATION_ARB ) {
496 this->gl_data->wglGetPixelFormatAttribivARB(GL_hdc, pixel_format, 0, 1, &wgl_attrib, value);
503 case SDL_GL_RED_SIZE:
504 *value = GL_pfd.cRedBits;
506 case SDL_GL_GREEN_SIZE:
507 *value = GL_pfd.cGreenBits;
509 case SDL_GL_BLUE_SIZE:
510 *value = GL_pfd.cBlueBits;
512 case SDL_GL_ALPHA_SIZE:
513 *value = GL_pfd.cAlphaBits;
515 case SDL_GL_DOUBLEBUFFER:
516 if ( GL_pfd.dwFlags & PFD_DOUBLEBUFFER ) {
522 case SDL_GL_BUFFER_SIZE:
523 *value = GL_pfd.cColorBits;
525 case SDL_GL_DEPTH_SIZE:
526 *value = GL_pfd.cDepthBits;
528 case SDL_GL_STENCIL_SIZE:
529 *value = GL_pfd.cStencilBits;
531 case SDL_GL_ACCUM_RED_SIZE:
532 *value = GL_pfd.cAccumRedBits;
534 case SDL_GL_ACCUM_GREEN_SIZE:
535 *value = GL_pfd.cAccumGreenBits;
537 case SDL_GL_ACCUM_BLUE_SIZE:
538 *value = GL_pfd.cAccumBlueBits;
540 case SDL_GL_ACCUM_ALPHA_SIZE:
541 *value = GL_pfd.cAccumAlphaBits;
544 if ( GL_pfd.dwFlags & PFD_STEREO ) {
550 case SDL_GL_MULTISAMPLEBUFFERS:
553 case SDL_GL_MULTISAMPLESAMPLES:
556 case SDL_GL_SWAP_CONTROL:
557 if ( this->gl_data->wglGetSwapIntervalEXT ) {
558 *value = this->gl_data->wglGetSwapIntervalEXT();
571 void WIN_GL_SwapBuffers(_THIS)
576 void WIN_GL_UnloadLibrary(_THIS)
578 if ( this->gl_config.driver_loaded ) {
579 FreeLibrary((HMODULE)this->gl_config.dll_handle);
581 this->gl_data->wglGetProcAddress = NULL;
582 this->gl_data->wglCreateContext = NULL;
583 this->gl_data->wglDeleteContext = NULL;
584 this->gl_data->wglMakeCurrent = NULL;
585 this->gl_data->wglGetPixelFormatAttribivARB = NULL;
586 this->gl_data->wglSwapIntervalEXT = NULL;
587 this->gl_data->wglGetSwapIntervalEXT = NULL;
589 this->gl_config.dll_handle = NULL;
590 this->gl_config.driver_loaded = 0;
594 /* Passing a NULL path means load pointers from the application */
595 int WIN_GL_LoadLibrary(_THIS, const char* path)
600 SDL_SetError("OpenGL context already created");
604 if ( path == NULL ) {
605 path = DEFAULT_GL_DRIVER_PATH;
607 handle = LoadLibrary(path);
608 if ( handle == NULL ) {
609 SDL_SetError("Could not load OpenGL library");
613 /* Unload the old driver and reset the pointers */
614 WIN_GL_UnloadLibrary(this);
616 /* Load new function pointers */
617 SDL_memset(this->gl_data, 0, sizeof(*this->gl_data));
618 this->gl_data->wglGetProcAddress = (void * (WINAPI *)(const char *))
619 GetProcAddress(handle, "wglGetProcAddress");
620 this->gl_data->wglCreateContext = (HGLRC (WINAPI *)(HDC))
621 GetProcAddress(handle, "wglCreateContext");
622 this->gl_data->wglDeleteContext = (BOOL (WINAPI *)(HGLRC))
623 GetProcAddress(handle, "wglDeleteContext");
624 this->gl_data->wglMakeCurrent = (BOOL (WINAPI *)(HDC, HGLRC))
625 GetProcAddress(handle, "wglMakeCurrent");
626 this->gl_data->wglSwapIntervalEXT = (void (WINAPI *)(int))
627 GetProcAddress(handle, "wglSwapIntervalEXT");
628 this->gl_data->wglGetSwapIntervalEXT = (int (WINAPI *)(void))
629 GetProcAddress(handle, "wglGetSwapIntervalEXT");
631 if ( (this->gl_data->wglGetProcAddress == NULL) ||
632 (this->gl_data->wglCreateContext == NULL) ||
633 (this->gl_data->wglDeleteContext == NULL) ||
634 (this->gl_data->wglMakeCurrent == NULL) ) {
635 SDL_SetError("Could not retrieve OpenGL functions");
640 this->gl_config.dll_handle = handle;
641 SDL_strlcpy(this->gl_config.driver_path, path, SDL_arraysize(this->gl_config.driver_path));
642 this->gl_config.driver_loaded = 1;
646 void *WIN_GL_GetProcAddress(_THIS, const char* proc)
650 /* This is to pick up extensions */
651 func = this->gl_data->wglGetProcAddress(proc);
653 /* This is probably a normal GL function */
654 func = GetProcAddress(this->gl_config.dll_handle, proc);
659 #endif /* SDL_VIDEO_OPENGL */