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@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) */
37static 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
80static 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
114static 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
172int 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
388void 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 */
410int 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. */
423int 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
571void WIN_GL_SwapBuffers(_THIS)
572{
573	SwapBuffers(GL_hdc);
574}
575
576void 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 */
595int 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
646void *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