Home | History | Annotate | Download | only in wincommon
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012 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 (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 /* WGL implementation of SDL OpenGL support */
     25 
     26 #if SDL_VIDEO_OPENGL
     27 #include "SDL_opengl.h"
     28 #endif
     29 #include "SDL_lowvideo.h"
     30 #include "SDL_wingl_c.h"
     31 
     32 #if SDL_VIDEO_OPENGL
     33 #define DEFAULT_GL_DRIVER_PATH "OPENGL32.DLL"
     34 #endif
     35 
     36 /* If setting the HDC fails, we may need to recreate the window (MSDN) */
     37 static int WIN_GL_ResetWindow(_THIS)
     38 {
     39 	int status = 0;
     40 
     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 */
     46 		LONG style;
     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();
     52 
     53 		SDL_resizing = 1;
     54 		SDL_Window = CreateWindow(SDL_Appname, SDL_Appname,
     55 		                          style,
     56 		                          rect.left, rect.top,
     57 		                          (rect.right-rect.left)+1,
     58 		                          (rect.bottom-rect.top)+1,
     59 		                          NULL, NULL, SDL_Instance, NULL);
     60 		WIN_FlushMessageQueue();
     61 		SDL_resizing = 0;
     62 
     63 		if ( SDL_Window ) {
     64 			this->SetCaption(this, this->wm_title, this->wm_icon);
     65 		} else {
     66 			SDL_SetError("Couldn't create window");
     67 			status = -1;
     68 		}
     69 	} else
     70 #endif /* !_WIN32_WCE */
     71 	{
     72 		SDL_SetError("Unable to reset window for OpenGL context");
     73 		status = -1;
     74 	}
     75 	return(status);
     76 }
     77 
     78 #if SDL_VIDEO_OPENGL
     79 
     80 static int ExtensionSupported(const char *extension, const char *extensions)
     81 {
     82 	const char *start;
     83 	const char *where, *terminator;
     84 
     85 	/* Extension names should not have spaces. */
     86 	where = SDL_strchr(extension, ' ');
     87 	if ( where || *extension == '\0' )
     88 	      return 0;
     89 
     90 	if ( ! extensions )
     91 		return 0;
     92 
     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,
     95 	 *           etc. */
     96 
     97 	start = extensions;
     98 
     99 	for (;;)
    100 	{
    101 		where = SDL_strstr(start, extension);
    102 		if (!where) break;
    103 
    104 		terminator = where + SDL_strlen(extension);
    105 		if (where == start || *(where - 1) == ' ')
    106 	        if (*terminator == ' ' || *terminator == '\0') return 1;
    107 
    108 		start = terminator;
    109 	}
    110 
    111 	return 0;
    112 }
    113 
    114 static int ChoosePixelFormatARB(_THIS, const int *iAttribs, const FLOAT *fAttribs)
    115 {
    116 	HWND hwnd;
    117 	HDC hdc;
    118 	HGLRC hglrc;
    119 	const char * (WINAPI *wglGetExtensionsStringARB)(HDC) = 0;
    120 	const char *extensions;
    121 	int pformat = 0;
    122 	UINT matches = 0;
    123 
    124 	hwnd = CreateWindow(SDL_Appname, SDL_Appname, WS_POPUP | WS_DISABLED,
    125 	                    0, 0, 10, 10,
    126 	                    NULL, NULL, SDL_Instance, NULL);
    127 	WIN_FlushMessageQueue();
    128 
    129 	hdc = GetDC(hwnd);
    130 
    131 	SetPixelFormat(hdc, ChoosePixelFormat(hdc, &GL_pfd), &GL_pfd);
    132 
    133 	hglrc = this->gl_data->wglCreateContext(hdc);
    134 	if ( hglrc ) {
    135 		this->gl_data->wglMakeCurrent(hdc, hglrc);
    136 	}
    137 
    138 	wglGetExtensionsStringARB = (const char * (WINAPI *)(HDC))
    139 		this->gl_data->wglGetProcAddress("wglGetExtensionsStringARB");
    140 
    141 	if( wglGetExtensionsStringARB ) {
    142 		extensions = wglGetExtensionsStringARB(hdc);
    143 	} else {
    144 		extensions = NULL;
    145 	}
    146 
    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;
    156 		}
    157 	}
    158 
    159 	if ( hglrc ) {
    160 		this->gl_data->wglMakeCurrent(NULL, NULL);
    161 		this->gl_data->wglDeleteContext(hglrc);
    162 	}
    163 	ReleaseDC(hwnd, hdc);
    164 	DestroyWindow(hwnd);
    165 	WIN_FlushMessageQueue();
    166 
    167 	return pformat;
    168 }
    169 
    170 #endif /* SDL_VIDEO_OPENGL */
    171 
    172 int WIN_GL_SetupWindow(_THIS)
    173 {
    174 	int retval;
    175 #if SDL_VIDEO_OPENGL
    176 	int i;
    177 	int iAttribs[64];
    178 	int *iAttr;
    179 	int *iAccelAttr = NULL;
    180 	float fAttribs[1] = { 0 };
    181 	const GLubyte *(WINAPI *glGetStringFunc)(GLenum);
    182 	const char *wglext;
    183 
    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 ) {
    188 			return(-1);
    189 		}
    190 	}
    191 
    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);
    195 	GL_pfd.nVersion = 1;
    196 	GL_pfd.dwFlags = (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL);
    197 	if ( this->gl_config.double_buffer ) {
    198 		GL_pfd.dwFlags |= PFD_DOUBLEBUFFER;
    199 	}
    200 	if ( this->gl_config.stereo ) {
    201 		GL_pfd.dwFlags |= PFD_STEREO;
    202 	}
    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;
    213 	GL_pfd.cAccumBits =
    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;
    218 
    219 	/* setup WGL_ARB_pixel_format attribs */
    220 	iAttr = &iAttribs[0];
    221 
    222 	*iAttr++ = WGL_DRAW_TO_WINDOW_ARB;
    223 	*iAttr++ = GL_TRUE;
    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;
    230 
    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;
    236 	iAccelAttr = iAttr;
    237 	if (this->gl_config.accelerated) {
    238 		*iAttr++ = WGL_FULL_ACCELERATION_ARB;
    239 	} else {
    240 		*iAttr++ = WGL_NO_ACCELERATION_ARB;
    241 	}
    242 
    243 	if ( this->gl_config.alpha_size ) {
    244 		*iAttr++ = WGL_ALPHA_BITS_ARB;
    245 		*iAttr++ = this->gl_config.alpha_size;
    246 	}
    247 
    248 	*iAttr++ = WGL_DOUBLE_BUFFER_ARB;
    249 	*iAttr++ = this->gl_config.double_buffer;
    250 
    251 	*iAttr++ = WGL_DEPTH_BITS_ARB;
    252 	*iAttr++ = this->gl_config.depth_size;
    253 
    254 	if ( this->gl_config.stencil_size ) {
    255 		*iAttr++ = WGL_STENCIL_BITS_ARB;
    256 		*iAttr++ = this->gl_config.stencil_size;
    257 	}
    258 
    259 	if ( this->gl_config.accum_red_size ) {
    260 		*iAttr++ = WGL_ACCUM_RED_BITS_ARB;
    261 		*iAttr++ = this->gl_config.accum_red_size;
    262 	}
    263 
    264 	if ( this->gl_config.accum_green_size ) {
    265 		*iAttr++ = WGL_ACCUM_GREEN_BITS_ARB;
    266 		*iAttr++ = this->gl_config.accum_green_size;
    267 	}
    268 
    269 	if ( this->gl_config.accum_blue_size ) {
    270 		*iAttr++ = WGL_ACCUM_BLUE_BITS_ARB;
    271 		*iAttr++ = this->gl_config.accum_blue_size;
    272 	}
    273 
    274 	if ( this->gl_config.accum_alpha_size ) {
    275 		*iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB;
    276 		*iAttr++ = this->gl_config.accum_alpha_size;
    277 	}
    278 
    279 	if ( this->gl_config.stereo ) {
    280 		*iAttr++ = WGL_STEREO_ARB;
    281 		*iAttr++ = GL_TRUE;
    282 	}
    283 
    284 	if ( this->gl_config.multisamplebuffers ) {
    285 		*iAttr++ = WGL_SAMPLE_BUFFERS_ARB;
    286 		*iAttr++ = this->gl_config.multisamplebuffers;
    287 	}
    288 
    289 	if ( this->gl_config.multisamplesamples ) {
    290 		*iAttr++ = WGL_SAMPLES_ARB;
    291 		*iAttr++ = this->gl_config.multisamplesamples;
    292 	}
    293 
    294 	*iAttr = 0;
    295 
    296 	for ( i=0; ; ++i ) {
    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");
    301 			return(-1);
    302 		}
    303 
    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. */
    311 		}
    312 		if ( !pixel_format ) {
    313 			pixel_format = ChoosePixelFormat(GL_hdc, &GL_pfd);
    314 		}
    315 		if ( !pixel_format ) {
    316 			SDL_SetError("No matching GL pixel format available");
    317 			return(-1);
    318 		}
    319 		if ( !SetPixelFormat(GL_hdc, pixel_format, &GL_pfd) ) {
    320 			if ( i == 0 ) {
    321 				/* First time through, try resetting the window */
    322 				if ( WIN_GL_ResetWindow(this) < 0 ) {
    323 					return(-1);
    324 				}
    325 				continue;
    326 			}
    327 			SDL_SetError("Unable to set HDC pixel format");
    328 			return(-1);
    329 		}
    330 		/* We either succeeded or failed by this point */
    331 		break;
    332 	}
    333 	DescribePixelFormat(GL_hdc, pixel_format, sizeof(GL_pfd), &GL_pfd);
    334 
    335 	GL_hrc = this->gl_data->wglCreateContext(GL_hdc);
    336 	if ( GL_hrc == NULL ) {
    337 		SDL_SetError("Unable to create GL context");
    338 		return(-1);
    339 	}
    340 	if ( WIN_GL_MakeCurrent(this) < 0 ) {
    341 		return(-1);
    342 	}
    343 	gl_active = 1;
    344 
    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");
    350 	} else {
    351 		this->gl_data->wglGetPixelFormatAttribivARB = NULL;
    352 	}
    353 
    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);
    361 	} else {
    362 		/* Uh oh, something is seriously wrong here... */
    363 		wglext = NULL;
    364 	}
    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");
    368 	} else {
    369 		this->gl_data->wglSwapIntervalEXT = NULL;
    370 		this->gl_data->wglGetSwapIntervalEXT = NULL;
    371 	}
    372 	if ( this->gl_config.swap_control >= 0 ) {
    373 		if ( this->gl_data->wglSwapIntervalEXT ) {
    374 			this->gl_data->wglSwapIntervalEXT(this->gl_config.swap_control);
    375 		}
    376 	}
    377 #else
    378 	SDL_SetError("WIN driver not configured with OpenGL");
    379 #endif
    380 	if ( gl_active ) {
    381 		retval = 0;
    382 	} else {
    383 		retval = -1;
    384 	}
    385 	return(retval);
    386 }
    387 
    388 void WIN_GL_ShutDown(_THIS)
    389 {
    390 #if SDL_VIDEO_OPENGL
    391 	/* Clean up OpenGL */
    392 	if ( GL_hrc ) {
    393 		this->gl_data->wglMakeCurrent(NULL, NULL);
    394 		this->gl_data->wglDeleteContext(GL_hrc);
    395 		GL_hrc = NULL;
    396 	}
    397 	if ( GL_hdc ) {
    398 		ReleaseDC(SDL_Window, GL_hdc);
    399 		GL_hdc = NULL;
    400 	}
    401 	gl_active = 0;
    402 
    403 	WIN_GL_UnloadLibrary(this);
    404 #endif /* SDL_VIDEO_OPENGL */
    405 }
    406 
    407 #if SDL_VIDEO_OPENGL
    408 
    409 /* Make the current context active */
    410 int WIN_GL_MakeCurrent(_THIS)
    411 {
    412 	int retval;
    413 
    414 	retval = 0;
    415 	if ( ! this->gl_data->wglMakeCurrent(GL_hdc, GL_hrc) ) {
    416 		SDL_SetError("Unable to make GL context current");
    417 		retval = -1;
    418 	}
    419 	return(retval);
    420 }
    421 
    422 /* Get attribute data from wgl. */
    423 int WIN_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value)
    424 {
    425 	int retval;
    426 
    427 	if (attrib == SDL_GL_SWAP_CONTROL) {
    428 		if ( this->gl_data->wglGetSwapIntervalEXT ) {
    429 			*value = this->gl_data->wglGetSwapIntervalEXT();
    430 			return 0;
    431 		}
    432 		return -1;
    433 	}
    434 
    435 	if ( this->gl_data->wglGetPixelFormatAttribivARB ) {
    436 		int wgl_attrib;
    437 
    438 		switch(attrib) {
    439 		    case SDL_GL_RED_SIZE:
    440 			wgl_attrib = WGL_RED_BITS_ARB;
    441 			break;
    442 		    case SDL_GL_GREEN_SIZE:
    443 			wgl_attrib = WGL_GREEN_BITS_ARB;
    444 			break;
    445 		    case SDL_GL_BLUE_SIZE:
    446 			wgl_attrib = WGL_BLUE_BITS_ARB;
    447 			break;
    448 		    case SDL_GL_ALPHA_SIZE:
    449 			wgl_attrib = WGL_ALPHA_BITS_ARB;
    450 			break;
    451 		    case SDL_GL_DOUBLEBUFFER:
    452 			wgl_attrib = WGL_DOUBLE_BUFFER_ARB;
    453 			break;
    454 		    case SDL_GL_BUFFER_SIZE:
    455 			wgl_attrib = WGL_COLOR_BITS_ARB;
    456 			break;
    457 		    case SDL_GL_DEPTH_SIZE:
    458 			wgl_attrib = WGL_DEPTH_BITS_ARB;
    459 			break;
    460 		    case SDL_GL_STENCIL_SIZE:
    461 			wgl_attrib = WGL_STENCIL_BITS_ARB;
    462 			break;
    463 		    case SDL_GL_ACCUM_RED_SIZE:
    464 			wgl_attrib = WGL_ACCUM_RED_BITS_ARB;
    465 			break;
    466 		    case SDL_GL_ACCUM_GREEN_SIZE:
    467 			wgl_attrib = WGL_ACCUM_GREEN_BITS_ARB;
    468 			break;
    469 		    case SDL_GL_ACCUM_BLUE_SIZE:
    470 			wgl_attrib = WGL_ACCUM_BLUE_BITS_ARB;
    471 			break;
    472 		    case SDL_GL_ACCUM_ALPHA_SIZE:
    473 			wgl_attrib = WGL_ACCUM_ALPHA_BITS_ARB;
    474 			break;
    475 		    case SDL_GL_STEREO:
    476 			wgl_attrib = WGL_STEREO_ARB;
    477 			break;
    478 		    case SDL_GL_MULTISAMPLEBUFFERS:
    479 			wgl_attrib = WGL_SAMPLE_BUFFERS_ARB;
    480 			break;
    481 		    case SDL_GL_MULTISAMPLESAMPLES:
    482 			wgl_attrib = WGL_SAMPLES_ARB;
    483 			break;
    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 ) {
    488 				*value = SDL_FALSE;
    489 			} else {
    490 				*value = SDL_TRUE;
    491 			}
    492 			return 0;
    493 		    default:
    494 			return(-1);
    495 		}
    496 		this->gl_data->wglGetPixelFormatAttribivARB(GL_hdc, pixel_format, 0, 1, &wgl_attrib, value);
    497 
    498 		return 0;
    499 	}
    500 
    501 	retval = 0;
    502 	switch ( attrib ) {
    503 	    case SDL_GL_RED_SIZE:
    504 		*value = GL_pfd.cRedBits;
    505 		break;
    506 	    case SDL_GL_GREEN_SIZE:
    507 		*value = GL_pfd.cGreenBits;
    508 		break;
    509 	    case SDL_GL_BLUE_SIZE:
    510 		*value = GL_pfd.cBlueBits;
    511 		break;
    512 	    case SDL_GL_ALPHA_SIZE:
    513 		*value = GL_pfd.cAlphaBits;
    514 		break;
    515 	    case SDL_GL_DOUBLEBUFFER:
    516 		if ( GL_pfd.dwFlags & PFD_DOUBLEBUFFER ) {
    517 			*value = 1;
    518 		} else {
    519 			*value = 0;
    520 		}
    521 		break;
    522 	    case SDL_GL_BUFFER_SIZE:
    523 		*value = GL_pfd.cColorBits;
    524 		break;
    525 	    case SDL_GL_DEPTH_SIZE:
    526 		*value = GL_pfd.cDepthBits;
    527 		break;
    528 	    case SDL_GL_STENCIL_SIZE:
    529 		*value = GL_pfd.cStencilBits;
    530 		break;
    531 	    case SDL_GL_ACCUM_RED_SIZE:
    532 		*value = GL_pfd.cAccumRedBits;
    533 		break;
    534 	    case SDL_GL_ACCUM_GREEN_SIZE:
    535 		*value = GL_pfd.cAccumGreenBits;
    536 		break;
    537 	    case SDL_GL_ACCUM_BLUE_SIZE:
    538 		*value = GL_pfd.cAccumBlueBits;
    539 		break;
    540 	    case SDL_GL_ACCUM_ALPHA_SIZE:
    541 		*value = GL_pfd.cAccumAlphaBits;
    542 		break;
    543 	    case SDL_GL_STEREO:
    544 		if ( GL_pfd.dwFlags & PFD_STEREO ) {
    545 			*value = 1;
    546 		} else {
    547 			*value = 0;
    548 		}
    549 		break;
    550 	    case SDL_GL_MULTISAMPLEBUFFERS:
    551 		*value = 0;
    552 		break;
    553 	    case SDL_GL_MULTISAMPLESAMPLES:
    554 		*value = 1;
    555 		break;
    556 	    case SDL_GL_SWAP_CONTROL:
    557 		if ( this->gl_data->wglGetSwapIntervalEXT ) {
    558 			*value = this->gl_data->wglGetSwapIntervalEXT();
    559 			return 0;
    560 		} else {
    561 			return -1;
    562 		}
    563 		break;
    564 	    default:
    565 		retval = -1;
    566 		break;
    567 	}
    568 	return retval;
    569 }
    570 
    571 void WIN_GL_SwapBuffers(_THIS)
    572 {
    573 	SwapBuffers(GL_hdc);
    574 }
    575 
    576 void WIN_GL_UnloadLibrary(_THIS)
    577 {
    578 	if ( this->gl_config.driver_loaded ) {
    579 		FreeLibrary((HMODULE)this->gl_config.dll_handle);
    580 
    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;
    588 
    589 		this->gl_config.dll_handle = NULL;
    590 		this->gl_config.driver_loaded = 0;
    591 	}
    592 }
    593 
    594 /* Passing a NULL path means load pointers from the application */
    595 int WIN_GL_LoadLibrary(_THIS, const char* path)
    596 {
    597 	HMODULE handle;
    598 
    599  	if ( gl_active ) {
    600  		SDL_SetError("OpenGL context already created");
    601  		return -1;
    602  	}
    603 
    604 	if ( path == NULL ) {
    605 		path = DEFAULT_GL_DRIVER_PATH;
    606 	}
    607 	handle = LoadLibrary(path);
    608 	if ( handle == NULL ) {
    609 		SDL_SetError("Could not load OpenGL library");
    610 		return -1;
    611 	}
    612 
    613 	/* Unload the old driver and reset the pointers */
    614 	WIN_GL_UnloadLibrary(this);
    615 
    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");
    630 
    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");
    636 		FreeLibrary(handle);
    637 		return -1;
    638 	}
    639 
    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;
    643 	return 0;
    644 }
    645 
    646 void *WIN_GL_GetProcAddress(_THIS, const char* proc)
    647 {
    648 	void *func;
    649 
    650 	/* This is to pick up extensions */
    651 	func = this->gl_data->wglGetProcAddress(proc);
    652 	if ( ! func ) {
    653 		/* This is probably a normal GL function */
    654 		func = GetProcAddress(this->gl_config.dll_handle, proc);
    655 	}
    656 	return func;
    657 }
    658 
    659 #endif /* SDL_VIDEO_OPENGL */
    660