2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 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 float fAttribs[1] = { 0 };
180 const GLubyte *(WINAPI *glGetStringFunc)(GLenum);
183 /* load the gl driver from a default path */
184 if ( ! this->gl_config.driver_loaded ) {
185 /* no driver has been loaded, use default (ourselves) */
186 if ( WIN_GL_LoadLibrary(this, NULL) < 0 ) {
191 /* Set up the pixel format descriptor with our needed format */
192 SDL_memset(&GL_pfd, 0, sizeof(GL_pfd));
193 GL_pfd.nSize = sizeof(GL_pfd);
195 GL_pfd.dwFlags = (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL);
196 if ( this->gl_config.double_buffer ) {
197 GL_pfd.dwFlags |= PFD_DOUBLEBUFFER;
199 if ( this->gl_config.stereo ) {
200 GL_pfd.dwFlags |= PFD_STEREO;
202 GL_pfd.iPixelType = PFD_TYPE_RGBA;
203 GL_pfd.cColorBits = this->gl_config.buffer_size;
204 GL_pfd.cRedBits = this->gl_config.red_size;
205 GL_pfd.cGreenBits = this->gl_config.green_size;
206 GL_pfd.cBlueBits = this->gl_config.blue_size;
207 GL_pfd.cAlphaBits = this->gl_config.alpha_size;
208 GL_pfd.cAccumRedBits = this->gl_config.accum_red_size;
209 GL_pfd.cAccumGreenBits = this->gl_config.accum_green_size;
210 GL_pfd.cAccumBlueBits = this->gl_config.accum_blue_size;
211 GL_pfd.cAccumAlphaBits = this->gl_config.accum_alpha_size;
213 (GL_pfd.cAccumRedBits + GL_pfd.cAccumGreenBits +
214 GL_pfd.cAccumBlueBits + GL_pfd.cAccumAlphaBits);
215 GL_pfd.cDepthBits = this->gl_config.depth_size;
216 GL_pfd.cStencilBits = this->gl_config.stencil_size;
218 /* setup WGL_ARB_pixel_format attribs */
219 iAttr = &iAttribs[0];
221 *iAttr++ = WGL_DRAW_TO_WINDOW_ARB;
223 *iAttr++ = WGL_ACCELERATION_ARB;
224 *iAttr++ = WGL_FULL_ACCELERATION_ARB;
225 *iAttr++ = WGL_RED_BITS_ARB;
226 *iAttr++ = this->gl_config.red_size;
227 *iAttr++ = WGL_GREEN_BITS_ARB;
228 *iAttr++ = this->gl_config.green_size;
229 *iAttr++ = WGL_BLUE_BITS_ARB;
230 *iAttr++ = this->gl_config.blue_size;
232 if ( this->gl_config.alpha_size ) {
233 *iAttr++ = WGL_ALPHA_BITS_ARB;
234 *iAttr++ = this->gl_config.alpha_size;
237 *iAttr++ = WGL_DOUBLE_BUFFER_ARB;
238 *iAttr++ = this->gl_config.double_buffer;
240 *iAttr++ = WGL_DEPTH_BITS_ARB;
241 *iAttr++ = this->gl_config.depth_size;
243 if ( this->gl_config.stencil_size ) {
244 *iAttr++ = WGL_STENCIL_BITS_ARB;
245 *iAttr++ = this->gl_config.stencil_size;
248 if ( this->gl_config.accum_red_size ) {
249 *iAttr++ = WGL_ACCUM_RED_BITS_ARB;
250 *iAttr++ = this->gl_config.accum_red_size;
253 if ( this->gl_config.accum_green_size ) {
254 *iAttr++ = WGL_ACCUM_GREEN_BITS_ARB;
255 *iAttr++ = this->gl_config.accum_green_size;
258 if ( this->gl_config.accum_blue_size ) {
259 *iAttr++ = WGL_ACCUM_BLUE_BITS_ARB;
260 *iAttr++ = this->gl_config.accum_blue_size;
263 if ( this->gl_config.accum_alpha_size ) {
264 *iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB;
265 *iAttr++ = this->gl_config.accum_alpha_size;
268 if ( this->gl_config.stereo ) {
269 *iAttr++ = WGL_STEREO_ARB;
273 if ( this->gl_config.multisamplebuffers ) {
274 *iAttr++ = WGL_SAMPLE_BUFFERS_ARB;
275 *iAttr++ = this->gl_config.multisamplebuffers;
278 if ( this->gl_config.multisamplesamples ) {
279 *iAttr++ = WGL_SAMPLES_ARB;
280 *iAttr++ = this->gl_config.multisamplesamples;
283 if ( this->gl_config.accelerated >= 0 ) {
284 *iAttr++ = WGL_ACCELERATION_ARB;
285 *iAttr++ = (this->gl_config.accelerated ? WGL_GENERIC_ACCELERATION_ARB : WGL_NO_ACCELERATION_ARB);
291 /* Get the window device context for our OpenGL drawing */
292 GL_hdc = GetDC(SDL_Window);
293 if ( GL_hdc == NULL ) {
294 SDL_SetError("Unable to get DC for SDL_Window");
298 /* Choose and set the closest available pixel format */
299 pixel_format = ChoosePixelFormatARB(this, iAttribs, fAttribs);
300 if ( !pixel_format ) {
301 pixel_format = ChoosePixelFormat(GL_hdc, &GL_pfd);
303 if ( !pixel_format ) {
304 SDL_SetError("No matching GL pixel format available");
307 if ( !SetPixelFormat(GL_hdc, pixel_format, &GL_pfd) ) {
309 /* First time through, try resetting the window */
310 if ( WIN_GL_ResetWindow(this) < 0 ) {
315 SDL_SetError("Unable to set HDC pixel format");
318 /* We either succeeded or failed by this point */
321 DescribePixelFormat(GL_hdc, pixel_format, sizeof(GL_pfd), &GL_pfd);
323 GL_hrc = this->gl_data->wglCreateContext(GL_hdc);
324 if ( GL_hrc == NULL ) {
325 SDL_SetError("Unable to create GL context");
328 if ( WIN_GL_MakeCurrent(this) < 0 ) {
333 /* Get the wglGetPixelFormatAttribivARB pointer for the context */
334 if ( this->gl_data->WGL_ARB_pixel_format ) {
335 this->gl_data->wglGetPixelFormatAttribivARB =
336 (BOOL (WINAPI *)(HDC, int, int, UINT, const int *, int *))
337 this->gl_data->wglGetProcAddress("wglGetPixelFormatAttribivARB");
339 this->gl_data->wglGetPixelFormatAttribivARB = NULL;
342 /* Vsync control under Windows. Checking glGetString here is
343 * somewhat a documented and reliable hack - it was originally
344 * as a feature added by mistake, but since so many people rely
345 * on it, it will not be removed. strstr should be safe here.*/
346 glGetStringFunc = WIN_GL_GetProcAddress(this, "glGetString");
347 if ( glGetStringFunc ) {
348 wglext = (const char *)glGetStringFunc(GL_EXTENSIONS);
350 /* Uh oh, something is seriously wrong here... */
353 if ( wglext && SDL_strstr(wglext, "WGL_EXT_swap_control") ) {
354 this->gl_data->wglSwapIntervalEXT = WIN_GL_GetProcAddress(this, "wglSwapIntervalEXT");
355 this->gl_data->wglGetSwapIntervalEXT = WIN_GL_GetProcAddress(this, "wglGetSwapIntervalEXT");
357 this->gl_data->wglSwapIntervalEXT = NULL;
358 this->gl_data->wglGetSwapIntervalEXT = NULL;
360 if ( this->gl_config.swap_control >= 0 ) {
361 if ( this->gl_data->wglSwapIntervalEXT ) {
362 this->gl_data->wglSwapIntervalEXT(this->gl_config.swap_control);
366 SDL_SetError("WIN driver not configured with OpenGL");
376 void WIN_GL_ShutDown(_THIS)
379 /* Clean up OpenGL */
381 this->gl_data->wglMakeCurrent(NULL, NULL);
382 this->gl_data->wglDeleteContext(GL_hrc);
386 ReleaseDC(SDL_Window, GL_hdc);
391 WIN_GL_UnloadLibrary(this);
392 #endif /* SDL_VIDEO_OPENGL */
397 /* Make the current context active */
398 int WIN_GL_MakeCurrent(_THIS)
403 if ( ! this->gl_data->wglMakeCurrent(GL_hdc, GL_hrc) ) {
404 SDL_SetError("Unable to make GL context current");
410 /* Get attribute data from wgl. */
411 int WIN_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value)
415 if (attrib == SDL_GL_SWAP_CONTROL) {
416 if ( this->gl_data->wglGetSwapIntervalEXT ) {
417 *value = this->gl_data->wglGetSwapIntervalEXT();
423 if ( this->gl_data->wglGetPixelFormatAttribivARB ) {
427 case SDL_GL_RED_SIZE:
428 wgl_attrib = WGL_RED_BITS_ARB;
430 case SDL_GL_GREEN_SIZE:
431 wgl_attrib = WGL_GREEN_BITS_ARB;
433 case SDL_GL_BLUE_SIZE:
434 wgl_attrib = WGL_BLUE_BITS_ARB;
436 case SDL_GL_ALPHA_SIZE:
437 wgl_attrib = WGL_ALPHA_BITS_ARB;
439 case SDL_GL_DOUBLEBUFFER:
440 wgl_attrib = WGL_DOUBLE_BUFFER_ARB;
442 case SDL_GL_BUFFER_SIZE:
443 wgl_attrib = WGL_COLOR_BITS_ARB;
445 case SDL_GL_DEPTH_SIZE:
446 wgl_attrib = WGL_DEPTH_BITS_ARB;
448 case SDL_GL_STENCIL_SIZE:
449 wgl_attrib = WGL_STENCIL_BITS_ARB;
451 case SDL_GL_ACCUM_RED_SIZE:
452 wgl_attrib = WGL_ACCUM_RED_BITS_ARB;
454 case SDL_GL_ACCUM_GREEN_SIZE:
455 wgl_attrib = WGL_ACCUM_GREEN_BITS_ARB;
457 case SDL_GL_ACCUM_BLUE_SIZE:
458 wgl_attrib = WGL_ACCUM_BLUE_BITS_ARB;
460 case SDL_GL_ACCUM_ALPHA_SIZE:
461 wgl_attrib = WGL_ACCUM_ALPHA_BITS_ARB;
464 wgl_attrib = WGL_STEREO_ARB;
466 case SDL_GL_MULTISAMPLEBUFFERS:
467 wgl_attrib = WGL_SAMPLE_BUFFERS_ARB;
469 case SDL_GL_MULTISAMPLESAMPLES:
470 wgl_attrib = WGL_SAMPLES_ARB;
472 case SDL_GL_ACCELERATED_VISUAL:
473 wgl_attrib = WGL_ACCELERATION_ARB;
474 this->gl_data->wglGetPixelFormatAttribivARB(GL_hdc, pixel_format, 0, 1, &wgl_attrib, value);
475 if ( *value == WGL_NO_ACCELERATION_ARB ) {
484 this->gl_data->wglGetPixelFormatAttribivARB(GL_hdc, pixel_format, 0, 1, &wgl_attrib, value);
491 case SDL_GL_RED_SIZE:
492 *value = GL_pfd.cRedBits;
494 case SDL_GL_GREEN_SIZE:
495 *value = GL_pfd.cGreenBits;
497 case SDL_GL_BLUE_SIZE:
498 *value = GL_pfd.cBlueBits;
500 case SDL_GL_ALPHA_SIZE:
501 *value = GL_pfd.cAlphaBits;
503 case SDL_GL_DOUBLEBUFFER:
504 if ( GL_pfd.dwFlags & PFD_DOUBLEBUFFER ) {
510 case SDL_GL_BUFFER_SIZE:
511 *value = GL_pfd.cColorBits;
513 case SDL_GL_DEPTH_SIZE:
514 *value = GL_pfd.cDepthBits;
516 case SDL_GL_STENCIL_SIZE:
517 *value = GL_pfd.cStencilBits;
519 case SDL_GL_ACCUM_RED_SIZE:
520 *value = GL_pfd.cAccumRedBits;
522 case SDL_GL_ACCUM_GREEN_SIZE:
523 *value = GL_pfd.cAccumGreenBits;
525 case SDL_GL_ACCUM_BLUE_SIZE:
526 *value = GL_pfd.cAccumBlueBits;
528 case SDL_GL_ACCUM_ALPHA_SIZE:
529 *value = GL_pfd.cAccumAlphaBits;
532 if ( GL_pfd.dwFlags & PFD_STEREO ) {
538 case SDL_GL_MULTISAMPLEBUFFERS:
541 case SDL_GL_MULTISAMPLESAMPLES:
544 case SDL_GL_SWAP_CONTROL:
545 if ( this->gl_data->wglGetSwapIntervalEXT ) {
546 *value = this->gl_data->wglGetSwapIntervalEXT();
559 void WIN_GL_SwapBuffers(_THIS)
564 void WIN_GL_UnloadLibrary(_THIS)
566 if ( this->gl_config.driver_loaded ) {
567 FreeLibrary((HMODULE)this->gl_config.dll_handle);
569 this->gl_data->wglGetProcAddress = NULL;
570 this->gl_data->wglCreateContext = NULL;
571 this->gl_data->wglDeleteContext = NULL;
572 this->gl_data->wglMakeCurrent = NULL;
573 this->gl_data->wglGetPixelFormatAttribivARB = NULL;
574 this->gl_data->wglSwapIntervalEXT = NULL;
575 this->gl_data->wglGetSwapIntervalEXT = NULL;
577 this->gl_config.dll_handle = NULL;
578 this->gl_config.driver_loaded = 0;
582 /* Passing a NULL path means load pointers from the application */
583 int WIN_GL_LoadLibrary(_THIS, const char* path)
588 SDL_SetError("OpenGL context already created");
592 if ( path == NULL ) {
593 path = DEFAULT_GL_DRIVER_PATH;
595 handle = LoadLibrary(path);
596 if ( handle == NULL ) {
597 SDL_SetError("Could not load OpenGL library");
601 /* Unload the old driver and reset the pointers */
602 WIN_GL_UnloadLibrary(this);
604 /* Load new function pointers */
605 SDL_memset(this->gl_data, 0, sizeof(*this->gl_data));
606 this->gl_data->wglGetProcAddress = (void * (WINAPI *)(const char *))
607 GetProcAddress(handle, "wglGetProcAddress");
608 this->gl_data->wglCreateContext = (HGLRC (WINAPI *)(HDC))
609 GetProcAddress(handle, "wglCreateContext");
610 this->gl_data->wglDeleteContext = (BOOL (WINAPI *)(HGLRC))
611 GetProcAddress(handle, "wglDeleteContext");
612 this->gl_data->wglMakeCurrent = (BOOL (WINAPI *)(HDC, HGLRC))
613 GetProcAddress(handle, "wglMakeCurrent");
614 this->gl_data->wglSwapIntervalEXT = (void (WINAPI *)(int))
615 GetProcAddress(handle, "wglSwapIntervalEXT");
616 this->gl_data->wglGetSwapIntervalEXT = (int (WINAPI *)(void))
617 GetProcAddress(handle, "wglGetSwapIntervalEXT");
619 if ( (this->gl_data->wglGetProcAddress == NULL) ||
620 (this->gl_data->wglCreateContext == NULL) ||
621 (this->gl_data->wglDeleteContext == NULL) ||
622 (this->gl_data->wglMakeCurrent == NULL) ) {
623 SDL_SetError("Could not retrieve OpenGL functions");
628 this->gl_config.dll_handle = handle;
629 SDL_strlcpy(this->gl_config.driver_path, path, SDL_arraysize(this->gl_config.driver_path));
630 this->gl_config.driver_loaded = 1;
634 void *WIN_GL_GetProcAddress(_THIS, const char* proc)
638 /* This is to pick up extensions */
639 func = this->gl_data->wglGetProcAddress(proc);
641 /* This is probably a normal GL function */
642 func = GetProcAddress(this->gl_config.dll_handle, proc);
647 #endif /* SDL_VIDEO_OPENGL */