2
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2006 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();
53
SDL_Window = CreateWindow(SDL_Appname, SDL_Appname,
56
(rect.right-rect.left)+1,
57
(rect.top-rect.bottom)+1,
58
NULL, NULL, SDL_Instance, NULL);
59
WIN_FlushMessageQueue();
62
this->SetCaption(this, this->wm_title, this->wm_icon);
64
SDL_SetError("Couldn't create window");
68
#endif /* !_WIN32_WCE */
70
SDL_SetError("Unable to reset window for OpenGL context");
78
static int ExtensionSupported(const char *extension, const char *extensions)
81
const char *where, *terminator;
83
/* Extension names should not have spaces. */
84
where = SDL_strchr(extension, ' ');
85
if ( where || *extension == '\0' )
91
/* It takes a bit of care to be fool-proof about parsing the
92
* OpenGL extensions string. Don't be fooled by sub-strings,
99
where = SDL_strstr(start, extension);
102
terminator = where + SDL_strlen(extension);
103
if (where == start || *(where - 1) == ' ')
104
if (*terminator == ' ' || *terminator == '\0') return 1;
112
static void Init_WGL_ARB_extensions(_THIS)
118
const char * (WINAPI *wglGetExtensionsStringARB)(HDC) = 0;
119
const char *extensions;
121
hwnd = CreateWindow(SDL_Appname, SDL_Appname, WS_POPUP | WS_DISABLED,
123
NULL, NULL, SDL_Instance, NULL);
124
WIN_FlushMessageQueue();
128
pformat = ChoosePixelFormat(hdc, &GL_pfd);
129
SetPixelFormat(hdc, pformat, &GL_pfd);
131
hglrc = this->gl_data->wglCreateContext(hdc);
133
this->gl_data->wglMakeCurrent(hdc, hglrc);
136
wglGetExtensionsStringARB = (const char * (WINAPI *)(HDC))
137
this->gl_data->wglGetProcAddress("wglGetExtensionsStringARB");
139
if( wglGetExtensionsStringARB ) {
140
extensions = wglGetExtensionsStringARB(hdc);
145
this->gl_data->WGL_ARB_pixel_format = 0;
146
if( ExtensionSupported("WGL_ARB_pixel_format", extensions) ) {
147
this->gl_data->wglChoosePixelFormatARB =
148
(BOOL (WINAPI *)(HDC, const int *, const FLOAT *, UINT, int *, UINT *))
149
this->gl_data->wglGetProcAddress("wglChoosePixelFormatARB");
150
this->gl_data->wglGetPixelFormatAttribivARB =
151
(BOOL (WINAPI *)(HDC, int, int, UINT, const int *, int *))
152
this->gl_data->wglGetProcAddress("wglGetPixelFormatAttribivARB");
154
if( (this->gl_data->wglChoosePixelFormatARB != NULL) &&
155
(this->gl_data->wglGetPixelFormatAttribivARB != NULL) ) {
156
this->gl_data->WGL_ARB_pixel_format = 1;
161
this->gl_data->wglMakeCurrent(NULL, NULL);
162
this->gl_data->wglDeleteContext(hglrc);
164
ReleaseDC(hwnd, hdc);
166
WIN_FlushMessageQueue();
169
#endif /* SDL_VIDEO_OPENGL */
171
int WIN_GL_SetupWindow(_THIS)
176
unsigned int matching;
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 ) {
192
/* Get the window device context for our OpenGL drawing */
193
GL_hdc = GetDC(SDL_Window);
194
if ( GL_hdc == NULL ) {
195
SDL_SetError("Unable to get DC for SDL_Window");
199
/* Set up the pixel format descriptor with our needed format */
200
SDL_memset(&GL_pfd, 0, sizeof(GL_pfd));
201
GL_pfd.nSize = sizeof(GL_pfd);
203
GL_pfd.dwFlags = (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL);
204
if ( this->gl_config.double_buffer ) {
205
GL_pfd.dwFlags |= PFD_DOUBLEBUFFER;
207
if ( this->gl_config.stereo ) {
208
GL_pfd.dwFlags |= PFD_STEREO;
210
GL_pfd.iPixelType = PFD_TYPE_RGBA;
211
GL_pfd.cColorBits = this->gl_config.buffer_size;
212
GL_pfd.cRedBits = this->gl_config.red_size;
213
GL_pfd.cGreenBits = this->gl_config.green_size;
214
GL_pfd.cBlueBits = this->gl_config.blue_size;
215
GL_pfd.cAlphaBits = this->gl_config.alpha_size;
216
GL_pfd.cAccumRedBits = this->gl_config.accum_red_size;
217
GL_pfd.cAccumGreenBits = this->gl_config.accum_green_size;
218
GL_pfd.cAccumBlueBits = this->gl_config.accum_blue_size;
219
GL_pfd.cAccumAlphaBits = this->gl_config.accum_alpha_size;
221
(GL_pfd.cAccumRedBits + GL_pfd.cAccumGreenBits +
222
GL_pfd.cAccumBlueBits + GL_pfd.cAccumAlphaBits);
223
GL_pfd.cDepthBits = this->gl_config.depth_size;
224
GL_pfd.cStencilBits = this->gl_config.stencil_size;
226
/* initialize WGL_ARB_pixel_format */
227
Init_WGL_ARB_extensions(this);
229
/* setup WGL_ARB_pixel_format attribs */
230
iAttr = &iAttribs[0];
232
*iAttr++ = WGL_DRAW_TO_WINDOW_ARB;
234
*iAttr++ = WGL_ACCELERATION_ARB;
235
*iAttr++ = WGL_FULL_ACCELERATION_ARB;
236
*iAttr++ = WGL_RED_BITS_ARB;
237
*iAttr++ = this->gl_config.red_size;
238
*iAttr++ = WGL_GREEN_BITS_ARB;
239
*iAttr++ = this->gl_config.green_size;
240
*iAttr++ = WGL_BLUE_BITS_ARB;
241
*iAttr++ = this->gl_config.blue_size;
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;
294
if ( this->gl_config.accelerated >= 0 ) {
295
*iAttr++ = WGL_ACCELERATION_ARB;
296
*iAttr++ = (this->gl_config.accelerated ? WGL_GENERIC_ACCELERATION_ARB : WGL_NO_ACCELERATION_ARB);
301
/* Choose and set the closest available pixel format */
302
if ( !this->gl_data->WGL_ARB_pixel_format ||
303
!this->gl_data->wglChoosePixelFormatARB(GL_hdc, iAttribs, fAttribs, 1, &pixel_format, &matching) ||
305
pixel_format = ChoosePixelFormat(GL_hdc, &GL_pfd);
306
this->gl_data->WGL_ARB_pixel_format = 0;
308
if ( !pixel_format ) {
309
SDL_SetError("No matching GL pixel format available");
312
if ( !SetPixelFormat(GL_hdc, pixel_format, &GL_pfd) ) {
314
/* First time through, try resetting the window */
315
if ( WIN_GL_ResetWindow(this) < 0 ) {
320
SDL_SetError("Unable to set HDC pixel format");
323
/* We either succeeded or failed by this point */
326
DescribePixelFormat(GL_hdc, pixel_format, sizeof(GL_pfd), &GL_pfd);
328
GL_hrc = this->gl_data->wglCreateContext(GL_hdc);
329
if ( GL_hrc == NULL ) {
330
SDL_SetError("Unable to create GL context");
333
if ( WIN_GL_MakeCurrent(this) < 0 ) {
338
/* Vsync control under Windows. Checking glGetString here is
339
* somewhat a documented and reliable hack - it was originally
340
* as a feature added by mistake, but since so many people rely
341
* on it, it will not be removed. strstr should be safe here.*/
342
glGetStringFunc = WIN_GL_GetProcAddress(this, "glGetString");
343
if ( glGetStringFunc ) {
344
wglext = (const char *)glGetStringFunc(GL_EXTENSIONS);
346
/* Uh oh, something is seriously wrong here... */
349
if ( !wglext || !SDL_strstr(wglext, "WGL_EXT_swap_control") ) {
350
this->gl_data->wglSwapIntervalEXT = NULL;
351
this->gl_data->wglGetSwapIntervalEXT = NULL;
353
if ( this->gl_config.swap_control >= 0 ) {
354
if ( this->gl_data->wglSwapIntervalEXT ) {
355
this->gl_data->wglSwapIntervalEXT(this->gl_config.swap_control);
359
SDL_SetError("WIN driver not configured with OpenGL");
369
void WIN_GL_ShutDown(_THIS)
372
/* Clean up OpenGL */
374
this->gl_data->wglMakeCurrent(NULL, NULL);
375
this->gl_data->wglDeleteContext(GL_hrc);
379
ReleaseDC(SDL_Window, GL_hdc);
384
WIN_GL_UnloadLibrary(this);
385
#endif /* SDL_VIDEO_OPENGL */
390
/* Make the current context active */
391
int WIN_GL_MakeCurrent(_THIS)
396
if ( ! this->gl_data->wglMakeCurrent(GL_hdc, GL_hrc) ) {
397
SDL_SetError("Unable to make GL context current");
403
/* Get attribute data from glX. */
404
int WIN_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value)
408
if ( this->gl_data->WGL_ARB_pixel_format ) {
412
case SDL_GL_RED_SIZE:
413
wgl_attrib = WGL_RED_BITS_ARB;
415
case SDL_GL_GREEN_SIZE:
416
wgl_attrib = WGL_GREEN_BITS_ARB;
418
case SDL_GL_BLUE_SIZE:
419
wgl_attrib = WGL_BLUE_BITS_ARB;
421
case SDL_GL_ALPHA_SIZE:
422
wgl_attrib = WGL_ALPHA_BITS_ARB;
424
case SDL_GL_DOUBLEBUFFER:
425
wgl_attrib = WGL_DOUBLE_BUFFER_ARB;
427
case SDL_GL_BUFFER_SIZE:
428
wgl_attrib = WGL_COLOR_BITS_ARB;
430
case SDL_GL_DEPTH_SIZE:
431
wgl_attrib = WGL_DEPTH_BITS_ARB;
433
case SDL_GL_STENCIL_SIZE:
434
wgl_attrib = WGL_STENCIL_BITS_ARB;
436
case SDL_GL_ACCUM_RED_SIZE:
437
wgl_attrib = WGL_ACCUM_RED_BITS_ARB;
439
case SDL_GL_ACCUM_GREEN_SIZE:
440
wgl_attrib = WGL_ACCUM_GREEN_BITS_ARB;
442
case SDL_GL_ACCUM_BLUE_SIZE:
443
wgl_attrib = WGL_ACCUM_BLUE_BITS_ARB;
445
case SDL_GL_ACCUM_ALPHA_SIZE:
446
wgl_attrib = WGL_ACCUM_ALPHA_BITS_ARB;
449
wgl_attrib = WGL_STEREO_ARB;
451
case SDL_GL_MULTISAMPLEBUFFERS:
452
wgl_attrib = WGL_SAMPLE_BUFFERS_ARB;
454
case SDL_GL_MULTISAMPLESAMPLES:
455
wgl_attrib = WGL_SAMPLES_ARB;
457
case SDL_GL_ACCELERATED_VISUAL:
458
wgl_attrib = WGL_ACCELERATION_ARB;
459
this->gl_data->wglGetPixelFormatAttribivARB(GL_hdc, pixel_format, 0, 1, &wgl_attrib, value);
460
if ( *value == WGL_NO_ACCELERATION_ARB ) {
467
case SDL_GL_SWAP_CONTROL:
468
if ( this->gl_data->wglGetSwapIntervalEXT ) {
469
return this->gl_data->wglGetSwapIntervalEXT();
476
this->gl_data->wglGetPixelFormatAttribivARB(GL_hdc, pixel_format, 0, 1, &wgl_attrib, value);
483
case SDL_GL_RED_SIZE:
484
*value = GL_pfd.cRedBits;
486
case SDL_GL_GREEN_SIZE:
487
*value = GL_pfd.cGreenBits;
489
case SDL_GL_BLUE_SIZE:
490
*value = GL_pfd.cBlueBits;
492
case SDL_GL_ALPHA_SIZE:
493
*value = GL_pfd.cAlphaBits;
495
case SDL_GL_DOUBLEBUFFER:
496
if ( GL_pfd.dwFlags & PFD_DOUBLEBUFFER ) {
502
case SDL_GL_BUFFER_SIZE:
503
*value = GL_pfd.cColorBits;
505
case SDL_GL_DEPTH_SIZE:
506
*value = GL_pfd.cDepthBits;
508
case SDL_GL_STENCIL_SIZE:
509
*value = GL_pfd.cStencilBits;
511
case SDL_GL_ACCUM_RED_SIZE:
512
*value = GL_pfd.cAccumRedBits;
514
case SDL_GL_ACCUM_GREEN_SIZE:
515
*value = GL_pfd.cAccumGreenBits;
517
case SDL_GL_ACCUM_BLUE_SIZE:
518
*value = GL_pfd.cAccumBlueBits;
520
case SDL_GL_ACCUM_ALPHA_SIZE:
521
*value = GL_pfd.cAccumAlphaBits;
524
if ( GL_pfd.dwFlags & PFD_STEREO ) {
530
case SDL_GL_MULTISAMPLEBUFFERS:
533
case SDL_GL_MULTISAMPLESAMPLES:
543
void WIN_GL_SwapBuffers(_THIS)
548
void WIN_GL_UnloadLibrary(_THIS)
550
if ( this->gl_config.driver_loaded ) {
551
FreeLibrary((HMODULE)this->gl_config.dll_handle);
553
this->gl_data->wglGetProcAddress = NULL;
554
this->gl_data->wglCreateContext = NULL;
555
this->gl_data->wglDeleteContext = NULL;
556
this->gl_data->wglMakeCurrent = NULL;
557
this->gl_data->wglChoosePixelFormatARB = NULL;
558
this->gl_data->wglGetPixelFormatAttribivARB = NULL;
559
this->gl_data->wglSwapIntervalEXT = NULL;
560
this->gl_data->wglGetSwapIntervalEXT = NULL;
562
this->gl_config.dll_handle = NULL;
563
this->gl_config.driver_loaded = 0;
567
/* Passing a NULL path means load pointers from the application */
568
int WIN_GL_LoadLibrary(_THIS, const char* path)
573
SDL_SetError("OpenGL context already created");
577
if ( path == NULL ) {
578
path = DEFAULT_GL_DRIVER_PATH;
580
handle = LoadLibrary(path);
581
if ( handle == NULL ) {
582
SDL_SetError("Could not load OpenGL library");
586
/* Unload the old driver and reset the pointers */
587
WIN_GL_UnloadLibrary(this);
589
/* Load new function pointers */
590
SDL_memset(this->gl_data, 0, sizeof(*this->gl_data));
591
this->gl_data->wglGetProcAddress = (void * (WINAPI *)(const char *))
592
GetProcAddress(handle, "wglGetProcAddress");
593
this->gl_data->wglCreateContext = (HGLRC (WINAPI *)(HDC))
594
GetProcAddress(handle, "wglCreateContext");
595
this->gl_data->wglDeleteContext = (BOOL (WINAPI *)(HGLRC))
596
GetProcAddress(handle, "wglDeleteContext");
597
this->gl_data->wglMakeCurrent = (BOOL (WINAPI *)(HDC, HGLRC))
598
GetProcAddress(handle, "wglMakeCurrent");
599
this->gl_data->wglSwapIntervalEXT = (void (WINAPI *)(int))
600
GetProcAddress(handle, "wglSwapIntervalEXT");
601
this->gl_data->wglGetSwapIntervalEXT = (int (WINAPI *)(void))
602
GetProcAddress(handle, "wglGetSwapIntervalEXT");
604
if ( (this->gl_data->wglGetProcAddress == NULL) ||
605
(this->gl_data->wglCreateContext == NULL) ||
606
(this->gl_data->wglDeleteContext == NULL) ||
607
(this->gl_data->wglMakeCurrent == NULL) ) {
608
SDL_SetError("Could not retrieve OpenGL functions");
613
this->gl_config.dll_handle = handle;
614
SDL_strlcpy(this->gl_config.driver_path, path, SDL_arraysize(this->gl_config.driver_path));
615
this->gl_config.driver_loaded = 1;
619
void *WIN_GL_GetProcAddress(_THIS, const char* proc)
623
/* This is to pick up extensions */
624
func = this->gl_data->wglGetProcAddress(proc);
626
/* This is probably a normal GL function */
627
func = GetProcAddress(this->gl_config.dll_handle, proc);
632
#endif /* SDL_VIDEO_OPENGL */