1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2006 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 float fAttribs[1] = { 0 }; 180 const GLubyte *(WINAPI *glGetStringFunc)(GLenum); 181 const char *wglext; 182 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 ) { 187 return(-1); 188 } 189 } 190 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); 194 GL_pfd.nVersion = 1; 195 GL_pfd.dwFlags = (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL); 196 if ( this->gl_config.double_buffer ) { 197 GL_pfd.dwFlags |= PFD_DOUBLEBUFFER; 198 } 199 if ( this->gl_config.stereo ) { 200 GL_pfd.dwFlags |= PFD_STEREO; 201 } 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; 212 GL_pfd.cAccumBits = 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; 217 218 /* setup WGL_ARB_pixel_format attribs */ 219 iAttr = &iAttribs[0]; 220 221 *iAttr++ = WGL_DRAW_TO_WINDOW_ARB; 222 *iAttr++ = GL_TRUE; 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; 231 232 if ( this->gl_config.alpha_size ) { 233 *iAttr++ = WGL_ALPHA_BITS_ARB; 234 *iAttr++ = this->gl_config.alpha_size; 235 } 236 237 *iAttr++ = WGL_DOUBLE_BUFFER_ARB; 238 *iAttr++ = this->gl_config.double_buffer; 239 240 *iAttr++ = WGL_DEPTH_BITS_ARB; 241 *iAttr++ = this->gl_config.depth_size; 242 243 if ( this->gl_config.stencil_size ) { 244 *iAttr++ = WGL_STENCIL_BITS_ARB; 245 *iAttr++ = this->gl_config.stencil_size; 246 } 247 248 if ( this->gl_config.accum_red_size ) { 249 *iAttr++ = WGL_ACCUM_RED_BITS_ARB; 250 *iAttr++ = this->gl_config.accum_red_size; 251 } 252 253 if ( this->gl_config.accum_green_size ) { 254 *iAttr++ = WGL_ACCUM_GREEN_BITS_ARB; 255 *iAttr++ = this->gl_config.accum_green_size; 256 } 257 258 if ( this->gl_config.accum_blue_size ) { 259 *iAttr++ = WGL_ACCUM_BLUE_BITS_ARB; 260 *iAttr++ = this->gl_config.accum_blue_size; 261 } 262 263 if ( this->gl_config.accum_alpha_size ) { 264 *iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB; 265 *iAttr++ = this->gl_config.accum_alpha_size; 266 } 267 268 if ( this->gl_config.stereo ) { 269 *iAttr++ = WGL_STEREO_ARB; 270 *iAttr++ = GL_TRUE; 271 } 272 273 if ( this->gl_config.multisamplebuffers ) { 274 *iAttr++ = WGL_SAMPLE_BUFFERS_ARB; 275 *iAttr++ = this->gl_config.multisamplebuffers; 276 } 277 278 if ( this->gl_config.multisamplesamples ) { 279 *iAttr++ = WGL_SAMPLES_ARB; 280 *iAttr++ = this->gl_config.multisamplesamples; 281 } 282 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); 286 } 287 288 *iAttr = 0; 289 290 for ( i=0; ; ++i ) { 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"); 295 return(-1); 296 } 297 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); 302 } 303 if ( !pixel_format ) { 304 SDL_SetError("No matching GL pixel format available"); 305 return(-1); 306 } 307 if ( !SetPixelFormat(GL_hdc, pixel_format, &GL_pfd) ) { 308 if ( i == 0 ) { 309 /* First time through, try resetting the window */ 310 if ( WIN_GL_ResetWindow(this) < 0 ) { 311 return(-1); 312 } 313 continue; 314 } 315 SDL_SetError("Unable to set HDC pixel format"); 316 return(-1); 317 } 318 /* We either succeeded or failed by this point */ 319 break; 320 } 321 DescribePixelFormat(GL_hdc, pixel_format, sizeof(GL_pfd), &GL_pfd); 322 323 GL_hrc = this->gl_data->wglCreateContext(GL_hdc); 324 if ( GL_hrc == NULL ) { 325 SDL_SetError("Unable to create GL context"); 326 return(-1); 327 } 328 if ( WIN_GL_MakeCurrent(this) < 0 ) { 329 return(-1); 330 } 331 gl_active = 1; 332 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"); 338 } else { 339 this->gl_data->wglGetPixelFormatAttribivARB = NULL; 340 } 341 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); 349 } else { 350 /* Uh oh, something is seriously wrong here... */ 351 wglext = NULL; 352 } 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"); 356 } else { 357 this->gl_data->wglSwapIntervalEXT = NULL; 358 this->gl_data->wglGetSwapIntervalEXT = NULL; 359 } 360 if ( this->gl_config.swap_control >= 0 ) { 361 if ( this->gl_data->wglSwapIntervalEXT ) { 362 this->gl_data->wglSwapIntervalEXT(this->gl_config.swap_control); 363 } 364 } 365 #else 366 SDL_SetError("WIN driver not configured with OpenGL"); 367 #endif 368 if ( gl_active ) { 369 retval = 0; 370 } else { 371 retval = -1; 372 } 373 return(retval); 374 } 375 376 void WIN_GL_ShutDown(_THIS) 377 { 378 #if SDL_VIDEO_OPENGL 379 /* Clean up OpenGL */ 380 if ( GL_hrc ) { 381 this->gl_data->wglMakeCurrent(NULL, NULL); 382 this->gl_data->wglDeleteContext(GL_hrc); 383 GL_hrc = NULL; 384 } 385 if ( GL_hdc ) { 386 ReleaseDC(SDL_Window, GL_hdc); 387 GL_hdc = NULL; 388 } 389 gl_active = 0; 390 391 WIN_GL_UnloadLibrary(this); 392 #endif /* SDL_VIDEO_OPENGL */ 393 } 394 395 #if SDL_VIDEO_OPENGL 396 397 /* Make the current context active */ 398 int WIN_GL_MakeCurrent(_THIS) 399 { 400 int retval; 401 402 retval = 0; 403 if ( ! this->gl_data->wglMakeCurrent(GL_hdc, GL_hrc) ) { 404 SDL_SetError("Unable to make GL context current"); 405 retval = -1; 406 } 407 return(retval); 408 } 409 410 /* Get attribute data from wgl. */ 411 int WIN_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value) 412 { 413 int retval; 414 415 if (attrib == SDL_GL_SWAP_CONTROL) { 416 if ( this->gl_data->wglGetSwapIntervalEXT ) { 417 *value = this->gl_data->wglGetSwapIntervalEXT(); 418 return 0; 419 } 420 return -1; 421 } 422 423 if ( this->gl_data->wglGetPixelFormatAttribivARB ) { 424 int wgl_attrib; 425 426 switch(attrib) { 427 case SDL_GL_RED_SIZE: 428 wgl_attrib = WGL_RED_BITS_ARB; 429 break; 430 case SDL_GL_GREEN_SIZE: 431 wgl_attrib = WGL_GREEN_BITS_ARB; 432 break; 433 case SDL_GL_BLUE_SIZE: 434 wgl_attrib = WGL_BLUE_BITS_ARB; 435 break; 436 case SDL_GL_ALPHA_SIZE: 437 wgl_attrib = WGL_ALPHA_BITS_ARB; 438 break; 439 case SDL_GL_DOUBLEBUFFER: 440 wgl_attrib = WGL_DOUBLE_BUFFER_ARB; 441 break; 442 case SDL_GL_BUFFER_SIZE: 443 wgl_attrib = WGL_COLOR_BITS_ARB; 444 break; 445 case SDL_GL_DEPTH_SIZE: 446 wgl_attrib = WGL_DEPTH_BITS_ARB; 447 break; 448 case SDL_GL_STENCIL_SIZE: 449 wgl_attrib = WGL_STENCIL_BITS_ARB; 450 break; 451 case SDL_GL_ACCUM_RED_SIZE: 452 wgl_attrib = WGL_ACCUM_RED_BITS_ARB; 453 break; 454 case SDL_GL_ACCUM_GREEN_SIZE: 455 wgl_attrib = WGL_ACCUM_GREEN_BITS_ARB; 456 break; 457 case SDL_GL_ACCUM_BLUE_SIZE: 458 wgl_attrib = WGL_ACCUM_BLUE_BITS_ARB; 459 break; 460 case SDL_GL_ACCUM_ALPHA_SIZE: 461 wgl_attrib = WGL_ACCUM_ALPHA_BITS_ARB; 462 break; 463 case SDL_GL_STEREO: 464 wgl_attrib = WGL_STEREO_ARB; 465 break; 466 case SDL_GL_MULTISAMPLEBUFFERS: 467 wgl_attrib = WGL_SAMPLE_BUFFERS_ARB; 468 break; 469 case SDL_GL_MULTISAMPLESAMPLES: 470 wgl_attrib = WGL_SAMPLES_ARB; 471 break; 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 ) { 476 *value = SDL_FALSE; 477 } else { 478 *value = SDL_TRUE; 479 } 480 return 0; 481 default: 482 return(-1); 483 } 484 this->gl_data->wglGetPixelFormatAttribivARB(GL_hdc, pixel_format, 0, 1, &wgl_attrib, value); 485 486 return 0; 487 } 488 489 retval = 0; 490 switch ( attrib ) { 491 case SDL_GL_RED_SIZE: 492 *value = GL_pfd.cRedBits; 493 break; 494 case SDL_GL_GREEN_SIZE: 495 *value = GL_pfd.cGreenBits; 496 break; 497 case SDL_GL_BLUE_SIZE: 498 *value = GL_pfd.cBlueBits; 499 break; 500 case SDL_GL_ALPHA_SIZE: 501 *value = GL_pfd.cAlphaBits; 502 break; 503 case SDL_GL_DOUBLEBUFFER: 504 if ( GL_pfd.dwFlags & PFD_DOUBLEBUFFER ) { 505 *value = 1; 506 } else { 507 *value = 0; 508 } 509 break; 510 case SDL_GL_BUFFER_SIZE: 511 *value = GL_pfd.cColorBits; 512 break; 513 case SDL_GL_DEPTH_SIZE: 514 *value = GL_pfd.cDepthBits; 515 break; 516 case SDL_GL_STENCIL_SIZE: 517 *value = GL_pfd.cStencilBits; 518 break; 519 case SDL_GL_ACCUM_RED_SIZE: 520 *value = GL_pfd.cAccumRedBits; 521 break; 522 case SDL_GL_ACCUM_GREEN_SIZE: 523 *value = GL_pfd.cAccumGreenBits; 524 break; 525 case SDL_GL_ACCUM_BLUE_SIZE: 526 *value = GL_pfd.cAccumBlueBits; 527 break; 528 case SDL_GL_ACCUM_ALPHA_SIZE: 529 *value = GL_pfd.cAccumAlphaBits; 530 break; 531 case SDL_GL_STEREO: 532 if ( GL_pfd.dwFlags & PFD_STEREO ) { 533 *value = 1; 534 } else { 535 *value = 0; 536 } 537 break; 538 case SDL_GL_MULTISAMPLEBUFFERS: 539 *value = 0; 540 break; 541 case SDL_GL_MULTISAMPLESAMPLES: 542 *value = 1; 543 break; 544 case SDL_GL_SWAP_CONTROL: 545 if ( this->gl_data->wglGetSwapIntervalEXT ) { 546 *value = this->gl_data->wglGetSwapIntervalEXT(); 547 return 0; 548 } else { 549 return -1; 550 } 551 break; 552 default: 553 retval = -1; 554 break; 555 } 556 return retval; 557 } 558 559 void WIN_GL_SwapBuffers(_THIS) 560 { 561 SwapBuffers(GL_hdc); 562 } 563 564 void WIN_GL_UnloadLibrary(_THIS) 565 { 566 if ( this->gl_config.driver_loaded ) { 567 FreeLibrary((HMODULE)this->gl_config.dll_handle); 568 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; 576 577 this->gl_config.dll_handle = NULL; 578 this->gl_config.driver_loaded = 0; 579 } 580 } 581 582 /* Passing a NULL path means load pointers from the application */ 583 int WIN_GL_LoadLibrary(_THIS, const char* path) 584 { 585 HMODULE handle; 586 587 if ( gl_active ) { 588 SDL_SetError("OpenGL context already created"); 589 return -1; 590 } 591 592 if ( path == NULL ) { 593 path = DEFAULT_GL_DRIVER_PATH; 594 } 595 handle = LoadLibrary(path); 596 if ( handle == NULL ) { 597 SDL_SetError("Could not load OpenGL library"); 598 return -1; 599 } 600 601 /* Unload the old driver and reset the pointers */ 602 WIN_GL_UnloadLibrary(this); 603 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"); 618 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"); 624 FreeLibrary(handle); 625 return -1; 626 } 627 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; 631 return 0; 632 } 633 634 void *WIN_GL_GetProcAddress(_THIS, const char* proc) 635 { 636 void *func; 637 638 /* This is to pick up extensions */ 639 func = this->gl_data->wglGetProcAddress(proc); 640 if ( ! func ) { 641 /* This is probably a normal GL function */ 642 func = GetProcAddress(this->gl_config.dll_handle, proc); 643 } 644 return func; 645 } 646 647 #endif /* SDL_VIDEO_OPENGL */ 648