src/video/wincommon/SDL_wingl.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 06 Jan 2006 13:20:10 +0000
changeset 1234 73676c1f56ee
parent 889 eac8c69b5706
child 1261 031e093ba2a5
permissions -rw-r--r--
For sanity's sake, removed the '&' when passing copy_row array to asm.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2004 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 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     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 #include <string.h>
    29 
    30 /* WGL implementation of SDL OpenGL support */
    31 
    32 #ifdef HAVE_OPENGL
    33 #include "SDL_opengl.h"
    34 #endif
    35 #include "SDL_error.h"
    36 #include "SDL_lowvideo.h"
    37 #include "SDL_wingl_c.h"
    38 
    39 #ifdef HAVE_OPENGL
    40 #define DEFAULT_GL_DRIVER_PATH "OPENGL32.DLL"
    41 #endif
    42 
    43 /* If setting the HDC fails, we may need to recreate the window (MSDN) */
    44 static int WIN_GL_ResetWindow(_THIS)
    45 {
    46 	int status = 0;
    47 	int can_reset = 1;
    48 
    49 	/* If we were passed a window, then we can't create a new one */
    50 	if ( SDL_windowid ) {
    51 		can_reset = 0;
    52 	}
    53 #if 0 /* This doesn't work with DirectX code (see CVS comments) */
    54 #ifndef _WIN32_WCE /* FIXME WinCE needs the UNICODE version of CreateWindow() */
    55 	if ( can_reset ) {
    56 		/* Save the existing window attributes */
    57 		LONG style;
    58 		RECT rect = { 0, 0, 0, 0 };
    59 		style = GetWindowLong(SDL_Window, GWL_STYLE);
    60 		GetWindowRect(SDL_Window, &rect);
    61 		DestroyWindow(SDL_Window);
    62 		SDL_Window = CreateWindow(SDL_Appname, SDL_Appname,
    63 		                          style,
    64 					  rect.left, rect.top,
    65                                           (rect.right-rect.left)+1,
    66                                           (rect.top-rect.bottom)+1,
    67 		                          NULL, NULL, SDL_Instance, NULL);
    68 		if ( SDL_Window ) {
    69 			this->SetCaption(this, this->wm_title, this->wm_icon);
    70 		} else {
    71 			SDL_SetError("Couldn't create window");
    72 			status = -1;
    73 		}
    74 	} else
    75 #endif /* !_WIN32_WCE */
    76 #endif
    77 	{
    78 		SDL_SetError("Unable to reset window for OpenGL context");
    79 		status = -1;
    80 	}
    81 	return(status);
    82 }
    83 
    84 #ifdef HAVE_OPENGL
    85 static void Init_WGL_ARB_extensions(_THIS)
    86 {
    87 	HWND hwnd;
    88 	HDC hdc;
    89 	HGLRC hglrc;
    90 	int pformat;
    91 	const char * (WINAPI *wglGetExtensionsStringARB)(HDC) = 0;
    92 	
    93 	hwnd = CreateWindow(SDL_Appname, SDL_Appname, WS_POPUP | WS_DISABLED,
    94 	                    0, 0, 10, 10,
    95 	                    NULL, NULL, SDL_Instance,NULL);
    96 	hdc = GetDC(hwnd);
    97 
    98 	pformat = ChoosePixelFormat(hdc, &GL_pfd);
    99 	SetPixelFormat(hdc, pformat, &GL_pfd);
   100 
   101 	hglrc = this->gl_data->wglCreateContext(hdc);
   102 	if ( hglrc ) {
   103 		this->gl_data->wglMakeCurrent(hdc, hglrc);
   104 	}
   105 
   106 	wglGetExtensionsStringARB = (const char * (WINAPI *)(HDC))
   107 		this->gl_data->wglGetProcAddress("wglGetExtensionsStringARB");
   108 
   109 	if(wglGetExtensionsStringARB && strstr(wglGetExtensionsStringARB(hdc),"WGL_ARB_pixel_format")) {
   110 		this->gl_data->wglChoosePixelFormatARB =
   111 			(BOOL (WINAPI *)(HDC, const int *, const FLOAT *, UINT, int *, UINT *))
   112 			this->gl_data->wglGetProcAddress("wglChoosePixelFormatARB");
   113 		this->gl_data->wglGetPixelFormatAttribivARB =
   114 			(BOOL (WINAPI *)(HDC, int, int, UINT, const int *, int *))
   115 			this->gl_data->wglGetProcAddress("wglGetPixelFormatAttribivARB");
   116 
   117 		if( (this->gl_data->wglChoosePixelFormatARB != NULL) &&
   118 		    (this->gl_data->wglGetPixelFormatAttribivARB != NULL) )
   119 			this->gl_data->wgl_arb_pixel_format = 1;
   120 		else 
   121 			this->gl_data->wgl_arb_pixel_format = 0;
   122 	} else {
   123 		this->gl_data->wgl_arb_pixel_format = 0;
   124 	}
   125 	
   126 	if ( hglrc ) {
   127 		this->gl_data->wglMakeCurrent(NULL, NULL);
   128 		this->gl_data->wglDeleteContext(hglrc);
   129 	}
   130 	ReleaseDC(hwnd, hdc);
   131 	DestroyWindow(hwnd);
   132 }
   133 #endif /* !HAVE_OPENGL */
   134 
   135 int WIN_GL_SetupWindow(_THIS)
   136 {
   137 	int retval;
   138 #ifdef HAVE_OPENGL
   139 	int i;
   140 	unsigned int matching;
   141 	int iAttribs[64];
   142 	int *iAttr;
   143 	float fAttribs[1] = { 0 };
   144 
   145 	/* load the gl driver from a default path */
   146 	if ( ! this->gl_config.driver_loaded ) {
   147 		/* no driver has been loaded, use default (ourselves) */
   148 		if ( WIN_GL_LoadLibrary(this, NULL) < 0 ) {
   149 			return(-1);
   150 		}
   151 	}
   152 
   153 	for ( i=0; ; ++i ) {
   154 		/* Get the window device context for our OpenGL drawing */
   155 		GL_hdc = GetDC(SDL_Window);
   156 		if ( GL_hdc == NULL ) {
   157 			SDL_SetError("Unable to get DC for SDL_Window");
   158 			return(-1);
   159 		}
   160 
   161 		/* Set up the pixel format descriptor with our needed format */
   162 		memset(&GL_pfd, 0, sizeof(GL_pfd));
   163 		GL_pfd.nSize = sizeof(GL_pfd);
   164 		GL_pfd.nVersion = 1;
   165 		GL_pfd.dwFlags = (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL);
   166 		if ( this->gl_config.double_buffer ) {
   167 			GL_pfd.dwFlags |= PFD_DOUBLEBUFFER;
   168 		}
   169 		if ( this->gl_config.stereo ) {
   170 			GL_pfd.dwFlags |= PFD_STEREO;
   171 		}
   172 		GL_pfd.iPixelType = PFD_TYPE_RGBA;
   173 		GL_pfd.cColorBits = this->gl_config.buffer_size;
   174 		GL_pfd.cRedBits = this->gl_config.red_size;
   175 		GL_pfd.cGreenBits = this->gl_config.green_size;
   176 		GL_pfd.cBlueBits = this->gl_config.blue_size;
   177 		GL_pfd.cAlphaBits = this->gl_config.alpha_size;
   178 		GL_pfd.cAccumRedBits = this->gl_config.accum_red_size;
   179 		GL_pfd.cAccumGreenBits = this->gl_config.accum_green_size;
   180 		GL_pfd.cAccumBlueBits = this->gl_config.accum_blue_size;
   181 		GL_pfd.cAccumAlphaBits = this->gl_config.accum_alpha_size;
   182 		GL_pfd.cAccumBits =
   183 			(GL_pfd.cAccumRedBits + GL_pfd.cAccumGreenBits +
   184 			 GL_pfd.cAccumBlueBits + GL_pfd.cAccumAlphaBits);
   185 		GL_pfd.cDepthBits = this->gl_config.depth_size;
   186 		GL_pfd.cStencilBits = this->gl_config.stencil_size;
   187 
   188 		/* initialize WGL_ARB_pixel_format */
   189 		Init_WGL_ARB_extensions(this);
   190 
   191 		/* setup WGL_ARB_pixel_format attribs */
   192 		iAttr = &iAttribs[0];
   193 
   194 		*iAttr++ = WGL_DRAW_TO_WINDOW_ARB;
   195 		*iAttr++ = GL_TRUE;
   196 		*iAttr++ = WGL_ACCELERATION_ARB;
   197 		*iAttr++ = WGL_FULL_ACCELERATION_ARB;
   198 		*iAttr++ = WGL_RED_BITS_ARB;
   199 		*iAttr++ = this->gl_config.red_size;
   200 		*iAttr++ = WGL_GREEN_BITS_ARB;
   201 		*iAttr++ = this->gl_config.green_size;
   202 		*iAttr++ = WGL_BLUE_BITS_ARB;
   203 		*iAttr++ = this->gl_config.blue_size;
   204 		
   205 		if ( this->gl_config.alpha_size ) {
   206 			*iAttr++ = WGL_ALPHA_BITS_ARB;
   207 			*iAttr++ = this->gl_config.alpha_size;
   208 		}
   209 
   210 		if ( this->gl_config.double_buffer ) {
   211 			*iAttr ++ = WGL_DOUBLE_BUFFER_ARB;
   212 			*iAttr ++ = GL_TRUE;
   213 		}
   214 
   215 		*iAttr++ = WGL_DEPTH_BITS_ARB;
   216 		*iAttr++ = this->gl_config.depth_size;
   217 
   218 		if ( this->gl_config.stencil_size ) {
   219 			*iAttr++ = WGL_STENCIL_BITS_ARB;
   220 			*iAttr++ = this->gl_config.stencil_size;
   221 		}
   222 
   223 		if ( this->gl_config.accum_red_size ) {
   224 			*iAttr++ = WGL_ACCUM_RED_BITS_ARB;
   225 			*iAttr++ = this->gl_config.accum_red_size;
   226 		}
   227 
   228 		if ( this->gl_config.accum_green_size ) {
   229 			*iAttr++ = WGL_ACCUM_GREEN_BITS_ARB;
   230 			*iAttr++ = this->gl_config.accum_green_size;
   231 		}
   232 
   233 		if ( this->gl_config.accum_blue_size ) {
   234 			*iAttr++ = WGL_ACCUM_BLUE_BITS_ARB;
   235 			*iAttr++ = this->gl_config.accum_blue_size;
   236 		}
   237 
   238 		if ( this->gl_config.accum_alpha_size ) {
   239 			*iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB;
   240 			*iAttr++ = this->gl_config.accum_alpha_size;
   241 		}
   242 
   243 		if ( this->gl_config.stereo ) {
   244 			*iAttr++ = WGL_STEREO_ARB;
   245 			*iAttr++ = this->gl_config.stereo;
   246 		}
   247 
   248 		if ( this->gl_config.multisamplebuffers ) {
   249 			*iAttr++ = WGL_SAMPLE_BUFFERS_ARB;
   250 			*iAttr++ = this->gl_config.multisamplebuffers;
   251 		}
   252 
   253 		if ( this->gl_config.multisamplesamples ) {
   254 			*iAttr++ = WGL_SAMPLES_ARB;
   255 			*iAttr++ = this->gl_config.multisamplesamples;
   256 		}
   257 
   258 		*iAttr = 0;
   259 
   260 		/* Choose and set the closest available pixel format */
   261 		if ( !this->gl_data->wgl_arb_pixel_format ||
   262 		     !this->gl_data->wglChoosePixelFormatARB(GL_hdc, iAttribs, fAttribs, 1, &pixel_format, &matching) ||
   263 		     !matching ) {
   264 			pixel_format = ChoosePixelFormat(GL_hdc, &GL_pfd);
   265 			this->gl_data->wgl_arb_pixel_format = 0;
   266 		}
   267 		if ( !pixel_format ) {
   268 			SDL_SetError("No matching GL pixel format available");
   269 			return(-1);
   270 		}
   271 		if ( !SetPixelFormat(GL_hdc, pixel_format, &GL_pfd) ) {
   272 			if ( i == 0 ) {
   273 				/* First time through, try resetting the window */
   274 				if ( WIN_GL_ResetWindow(this) < 0 ) {
   275 					return(-1);
   276 				}
   277 				continue;
   278 			}
   279 			SDL_SetError("Unable to set HDC pixel format");
   280 			return(-1);
   281 		}
   282 		/* We either succeeded or failed by this point */
   283 		break;
   284 	}
   285 	DescribePixelFormat(GL_hdc, pixel_format, sizeof(GL_pfd), &GL_pfd);
   286 
   287 	GL_hrc = this->gl_data->wglCreateContext(GL_hdc);
   288 	if ( GL_hrc == NULL ) {
   289 		SDL_SetError("Unable to create GL context");
   290 		return(-1);
   291 	}
   292 	gl_active = 1;
   293 #else
   294 	SDL_SetError("WIN driver not configured with OpenGL");
   295 #endif
   296 	if ( gl_active ) {
   297 		retval = 0;
   298 	} else {
   299 		retval = -1;
   300 	}
   301 	return(retval);
   302 }
   303 
   304 void WIN_GL_ShutDown(_THIS)
   305 {
   306 #ifdef HAVE_OPENGL
   307 	/* Clean up OpenGL */
   308 	if ( GL_hrc ) {
   309 		this->gl_data->wglMakeCurrent(NULL, NULL);
   310 		this->gl_data->wglDeleteContext(GL_hrc);
   311 		GL_hrc = NULL;
   312 	}
   313 	if ( GL_hdc ) {
   314 		ReleaseDC(SDL_Window, GL_hdc);
   315 		GL_hdc = NULL;
   316 	}
   317 	gl_active = 0;
   318 
   319 	WIN_GL_UnloadLibrary(this);
   320 #endif /* HAVE_OPENGL */
   321 }
   322 
   323 #ifdef HAVE_OPENGL
   324 
   325 /* Make the current context active */
   326 int WIN_GL_MakeCurrent(_THIS)
   327 {
   328 	int retval;
   329 
   330 	retval = 0;
   331 	if ( ! this->gl_data->wglMakeCurrent(GL_hdc, GL_hrc) ) {
   332 		SDL_SetError("Unable to make GL context current");
   333 		retval = -1;
   334 	}
   335 	return(retval);
   336 }
   337 
   338 /* Get attribute data from glX. */
   339 int WIN_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value)
   340 {
   341 	int retval;
   342 	
   343 	if ( this->gl_data->wgl_arb_pixel_format ) {
   344 		int wgl_attrib;
   345 
   346 		switch(attrib) {
   347 		    case SDL_GL_RED_SIZE:
   348 			wgl_attrib = WGL_RED_BITS_ARB;
   349 			break;
   350 		    case SDL_GL_GREEN_SIZE:
   351 			wgl_attrib = WGL_GREEN_BITS_ARB;
   352 			break;
   353 		    case SDL_GL_BLUE_SIZE:
   354 			wgl_attrib = WGL_BLUE_BITS_ARB;
   355 			break;
   356 		    case SDL_GL_ALPHA_SIZE:
   357 			wgl_attrib = WGL_ALPHA_BITS_ARB;
   358 			break;
   359 		    case SDL_GL_DOUBLEBUFFER:
   360 			wgl_attrib = WGL_DOUBLE_BUFFER_ARB;
   361 			break;
   362 		    case SDL_GL_BUFFER_SIZE:
   363 			wgl_attrib = WGL_COLOR_BITS_ARB;
   364 			break;
   365 		    case SDL_GL_DEPTH_SIZE:
   366 			wgl_attrib = WGL_DEPTH_BITS_ARB;
   367 			break;
   368 		    case SDL_GL_STENCIL_SIZE:
   369 			wgl_attrib = WGL_STENCIL_BITS_ARB;
   370 			break;
   371 		    case SDL_GL_ACCUM_RED_SIZE:
   372 			wgl_attrib = WGL_ACCUM_RED_BITS_ARB;
   373 			break;
   374 		    case SDL_GL_ACCUM_GREEN_SIZE:
   375 			wgl_attrib = WGL_ACCUM_GREEN_BITS_ARB;
   376 			break;
   377 		    case SDL_GL_ACCUM_BLUE_SIZE:
   378 			wgl_attrib = WGL_ACCUM_BLUE_BITS_ARB;
   379 			break;
   380 		    case SDL_GL_ACCUM_ALPHA_SIZE:
   381 			wgl_attrib = WGL_ACCUM_ALPHA_BITS_ARB;
   382 			break;
   383 		    case SDL_GL_STEREO:
   384 			wgl_attrib = WGL_STEREO_ARB;
   385 			break;
   386 		    case SDL_GL_MULTISAMPLEBUFFERS:
   387 			wgl_attrib = WGL_SAMPLE_BUFFERS_ARB;
   388 			break;
   389 		    case SDL_GL_MULTISAMPLESAMPLES:
   390 			wgl_attrib = WGL_SAMPLES_ARB;
   391 			break;
   392 		    default:
   393 			return(-1);
   394 		}
   395 		this->gl_data->wglGetPixelFormatAttribivARB(GL_hdc, pixel_format, 0, 1, &wgl_attrib, value);
   396 
   397 		return 0;
   398 	}
   399 
   400 	retval = 0;
   401 	switch ( attrib ) {
   402 	    case SDL_GL_RED_SIZE:
   403 		*value = GL_pfd.cRedBits;
   404 		break;
   405 	    case SDL_GL_GREEN_SIZE:
   406 		*value = GL_pfd.cGreenBits;
   407 		break;
   408 	    case SDL_GL_BLUE_SIZE:
   409 		*value = GL_pfd.cBlueBits;
   410 		break;
   411 	    case SDL_GL_ALPHA_SIZE:
   412 		*value = GL_pfd.cAlphaBits;
   413 		break;
   414 	    case SDL_GL_DOUBLEBUFFER:
   415 		if ( GL_pfd.dwFlags & PFD_DOUBLEBUFFER ) {
   416 			*value = 1;
   417 		} else {
   418 			*value = 0;
   419 		}
   420 		break;
   421 	    case SDL_GL_BUFFER_SIZE:
   422 		*value = GL_pfd.cColorBits;
   423 		break;
   424 	    case SDL_GL_DEPTH_SIZE:
   425 		*value = GL_pfd.cDepthBits;
   426 		break;
   427 	    case SDL_GL_STENCIL_SIZE:
   428 		*value = GL_pfd.cStencilBits;
   429 		break;
   430 	    case SDL_GL_ACCUM_RED_SIZE:
   431 		*value = GL_pfd.cAccumRedBits;
   432 		break;
   433 	    case SDL_GL_ACCUM_GREEN_SIZE:
   434 		*value = GL_pfd.cAccumGreenBits;
   435 		break;
   436 	    case SDL_GL_ACCUM_BLUE_SIZE:
   437 		*value = GL_pfd.cAccumBlueBits;
   438 		break;
   439 	    case SDL_GL_ACCUM_ALPHA_SIZE:
   440 		*value = GL_pfd.cAccumAlphaBits;
   441 		break;
   442 	    case SDL_GL_STEREO:
   443 		if ( GL_pfd.dwFlags & PFD_STEREO ) {
   444 			*value = 1;
   445 		} else {
   446 			*value = 0;
   447 		}
   448 		break;
   449 	    default:
   450 		retval = -1;
   451 		break;
   452 	}
   453 	return retval;
   454 }
   455 
   456 void WIN_GL_SwapBuffers(_THIS)
   457 {
   458 	SwapBuffers(GL_hdc);
   459 }
   460 
   461 void WIN_GL_UnloadLibrary(_THIS)
   462 {
   463 	if ( this->gl_config.driver_loaded ) {
   464 		FreeLibrary((HMODULE)this->gl_config.dll_handle);
   465 
   466 		this->gl_data->wglGetProcAddress = NULL;
   467 		this->gl_data->wglCreateContext = NULL;
   468 		this->gl_data->wglDeleteContext = NULL;
   469 		this->gl_data->wglMakeCurrent = NULL;
   470 		this->gl_data->wglChoosePixelFormatARB = NULL;
   471 		this->gl_data->wglGetPixelFormatAttribivARB = NULL;
   472 
   473 		this->gl_config.dll_handle = NULL;
   474 		this->gl_config.driver_loaded = 0;
   475 	}
   476 }
   477 
   478 /* Passing a NULL path means load pointers from the application */
   479 int WIN_GL_LoadLibrary(_THIS, const char* path) 
   480 {
   481 	HMODULE handle;
   482 
   483  	if ( gl_active ) {
   484  		SDL_SetError("OpenGL context already created");
   485  		return -1;
   486  	}
   487 
   488 	if ( path == NULL ) {
   489 		path = DEFAULT_GL_DRIVER_PATH;
   490 	}
   491 	handle = LoadLibrary(path);
   492 	if ( handle == NULL ) {
   493 		SDL_SetError("Could not load OpenGL library");
   494 		return -1;
   495 	}
   496 
   497 	/* Unload the old driver and reset the pointers */
   498 	WIN_GL_UnloadLibrary(this);
   499 
   500 	/* Load new function pointers */
   501 	memset(this->gl_data, 0, sizeof(*this->gl_data));
   502 	this->gl_data->wglGetProcAddress = (void * (WINAPI *)(const char *))
   503 		GetProcAddress(handle, "wglGetProcAddress");
   504 	this->gl_data->wglCreateContext = (HGLRC (WINAPI *)(HDC))
   505 		GetProcAddress(handle, "wglCreateContext");
   506 	this->gl_data->wglDeleteContext = (BOOL (WINAPI *)(HGLRC))
   507 		GetProcAddress(handle, "wglDeleteContext");
   508 	this->gl_data->wglMakeCurrent = (BOOL (WINAPI *)(HDC, HGLRC))
   509 		GetProcAddress(handle, "wglMakeCurrent");
   510 
   511 	if ( (this->gl_data->wglGetProcAddress == NULL) ||
   512 	     (this->gl_data->wglCreateContext == NULL) ||
   513 	     (this->gl_data->wglDeleteContext == NULL) ||
   514 	     (this->gl_data->wglMakeCurrent == NULL) ) {
   515 		SDL_SetError("Could not retrieve OpenGL functions");
   516 		FreeLibrary(handle);
   517 		return -1;
   518 	}
   519 
   520 	this->gl_config.dll_handle = handle;
   521 	strcpy(this->gl_config.driver_path, path);
   522 	this->gl_config.driver_loaded = 1;
   523 	return 0;
   524 }
   525 
   526 void *WIN_GL_GetProcAddress(_THIS, const char* proc)
   527 {
   528 	void *func;
   529 
   530 	/* This is to pick up extensions */
   531 	func = this->gl_data->wglGetProcAddress(proc);
   532 	if ( ! func ) {
   533 		/* This is probably a normal GL function */
   534 		func = GetProcAddress(this->gl_config.dll_handle, proc);
   535 	}
   536 	return func;
   537 }
   538 
   539 #endif /* HAVE_OPENGL */