1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 /*
21 ** GLW_IMP.C
22 **
23 ** This file contains ALL Win32 specific stuff having to do with the
24 ** OpenGL refresh.  When a port is being made the following functions
25 ** must be implemented by the port:
26 **
27 ** GLimp_EndFrame
28 ** GLimp_Init
29 ** GLimp_Shutdown
30 ** GLimp_SwitchFullscreen
31 **
32 */
33 
34 #include "win_local.h"
35 #include "win_glimp.h"
36 #include "win_wgl.h"
37 
38 glwstate_t glw_state;
39 
40 static cvar_t	*glw_driver;
41 static cvar_t	*glw_allow_software;
42 static cvar_t	*glw_drawbuffer;
43 static cvar_t	*glw_bitdepth;
44 static cvar_t	*glw_stereo;
45 static cvar_t	*vid_flip_on_switch;
46 static cvar_t	*vid_displayfrequency;
47 
GLimp_FatalShutdown(void)48 void GLimp_FatalShutdown( void ) {
49 	if( glw_state.flags & QVF_GAMMARAMP_ENABLED ) {
50 		if( glw_state.hDC ) {
51 			SetDeviceGammaRamp( glw_state.hDC, glw_state.originalGammaRamp );
52 		}
53 		glw_state.flags &= ~QVF_GAMMARAMP_ENABLED;
54 	}
55 
56 	if( glw_state.hWnd ) {
57 		DestroyWindow( glw_state.hWnd );
58 		glw_state.hWnd = NULL;
59 	}
60 
61 	if( glw_state.flags & QVF_FULLSCREEN_ENABLED ) {
62 		ChangeDisplaySettings( 0, 0 );
63 		glw_state.flags &= ~QVF_FULLSCREEN_ENABLED;
64 	}
65 }
66 
67 /*
68 ** GLimp_Shutdown
69 **
70 ** This routine does all OS specific shutdown procedures for the OpenGL
71 ** subsystem.  Under OpenGL this means NULLing out the current DC and
72 ** HGLRC, deleting the rendering context, and releasing the DC acquired
73 ** for the window.  The state structure is also nulled out.
74 **
75 */
GLimp_Shutdown(void)76 static void GLimp_Shutdown( void ) {
77 	Com_Printf( "Shutting down OpenGL subsystem...\n" );
78 
79 	if( glw_state.flags & QVF_GAMMARAMP_ENABLED ) {
80 		if( glw_state.hDC ) {
81 			Com_Printf( "...restoring gamma settings: " );
82 			if( !SetDeviceGammaRamp( glw_state.hDC, glw_state.originalGammaRamp ) ) {
83 				Com_Printf( "failed\n" );
84 			} else {
85 				Com_Printf( "ok\n" );
86 			}
87 		}
88 		glw_state.flags &= ~QVF_GAMMARAMP_ENABLED;
89 	}
90 
91 	if( qwglMakeCurrent ) {
92 		Com_Printf( "...making context not current: " );
93 		if( !qwglMakeCurrent( NULL, NULL ) ) {
94 			Com_Printf( "failed\n" );
95 		} else {
96 			Com_Printf( "ok\n" );
97 		}
98 	}
99 
100 	if( glw_state.hGLRC ) {
101 		Com_Printf( "...deleting OpenGL context: " );
102 		if( !qwglDeleteContext( glw_state.hGLRC ) ) {
103 			Com_Printf( "failed\n" );
104 		} else {
105 			Com_Printf( "ok\n" );
106 		}
107 		glw_state.hGLRC = NULL;
108 	}
109 
110 	if( glw_state.hDC ) {
111 		Com_Printf( "...releasing DC: " );
112 		if( !ReleaseDC( glw_state.hWnd, glw_state.hDC ) ) {
113 			Com_Printf( "failed\n" );
114 		} else {
115 			Com_Printf( "ok\n" );
116 		}
117 		glw_state.hDC = NULL;
118 	}
119 
120 	if( glw_state.hWnd ) {
121 		Com_Printf( "...destroying window\n" );
122 		Win_DestroyWindow( glw_state.hWnd );
123 		glw_state.hWnd = NULL;
124 	}
125 
126 	if( glw_state.flags & QVF_FULLSCREEN_ENABLED ) {
127 		ChangeDisplaySettings( 0, 0 );
128 		glw_state.flags &= ~QVF_FULLSCREEN_ENABLED;
129 	}
130 
131 	WGL_Shutdown();
132 }
133 
134 
135 /*
136 ** GLimp_Init
137 **
138 ** This routine is responsible for initializing the OS specific portions
139 ** of OpenGL.  Under Win32 this means dealing with the pixelformats and
140 ** doing the wgl interface stuff.
141 */
GLimp_Init(void)142 static qboolean GLimp_Init( void ) {
143 	OSVERSIONINFO	vinfo;
144 
145 	// Com_Printf( "Initializing OpenGL subsystem\n" );
146 
147 	Win_Init();
148 
149 	vinfo.dwOSVersionInfoSize = sizeof( vinfo );
150 
151 	if( !GetVersionEx( &vinfo ) ) {
152 		Com_Error( ERR_FATAL, "GLimp_Init: GetVersionEx failed" );
153 	}
154 
155 	glw_state.allowdisplaydepthchange = qfalse;
156 	if( vinfo.dwMajorVersion > 4 ) {
157 		glw_state.allowdisplaydepthchange = qtrue;
158 	} else if ( vinfo.dwMajorVersion == 4 ) {
159 		if( vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) {
160 			glw_state.allowdisplaydepthchange = qtrue;
161 		} else if( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) {
162 			if( LOWORD( vinfo.dwBuildNumber ) >= 1111 ) {
163 				glw_state.allowdisplaydepthchange = qtrue;
164 			}
165 		}
166 	}
167 
168 	Cvar_Subsystem( CVAR_SYSTEM_VIDEO );
169 
170 	glw_driver = Cvar_Get( "gl_driver", "opengl32", CVAR_ARCHIVE|CVAR_LATCHED );
171 	glw_drawbuffer = Cvar_Get( "gl_drawbuffer", "GL_BACK", 0 );
172 	glw_bitdepth = Cvar_Get( "gl_bitdepth", "0", CVAR_LATCHED );
173 	glw_allow_software = Cvar_Get( "gl_allow_software", "0", CVAR_LATCHED );
174 	glw_stereo = Cvar_Get( "cl_stereo", "0", CVAR_LATCHED );
175 	vid_flip_on_switch = Cvar_Get( "vid_flip_on_switch", "0", 0 );
176 	vid_displayfrequency = Cvar_Get( "vid_displayfrequency", "0", CVAR_LATCHED );
177 
178 	Cvar_Subsystem( CVAR_SYSTEM_GENERIC );
179 
180 	return qtrue;
181 }
182 
GLimp_VerifyDriver(void)183 static qboolean GLimp_VerifyDriver( void ) {
184 	char buffer[MAX_STRING_CHARS];
185 
186 	Q_strncpyz( buffer, qglGetString( GL_RENDERER ), sizeof( buffer ) );
187 	Q_strlwr( buffer );
188 	if( strcmp( buffer, "gdi generic" ) == 0 )
189 		if( !( glw_state.flags & QVF_ACCELERATED ) )
190 			return qfalse;
191 	return qtrue;
192 }
193 
GLimp_InitGL(int width,int height,qboolean fullscreen)194 static qboolean GLimp_InitGL( int width, int height, qboolean fullscreen ) {
195     PIXELFORMATDESCRIPTOR pfd = {
196 		sizeof( PIXELFORMATDESCRIPTOR ),	// size of this pfd
197 		1,								// version number
198 		PFD_DRAW_TO_WINDOW |			// support window
199 		PFD_SUPPORT_OPENGL |			// support OpenGL
200 		PFD_DOUBLEBUFFER,				// double buffered
201 		PFD_TYPE_RGBA,					// RGBA type
202 		24,								// 24-bit color depth
203 		0, 0, 0, 0, 0, 0,				// color bits ignored
204 		0,								// no alpha buffer
205 		0,								// shift bit ignored
206 		0,								// no accumulation buffer
207 		0, 0, 0, 0, 					// accum bits ignored
208 		32,								// 32-bit z-buffer
209 		0,								// no stencil buffer
210 		0,								// no auxiliary buffer
211 		PFD_MAIN_PLANE,					// main layer
212 		0,								// reserved
213 		0, 0, 0							// layer masks ignored
214     };
215     int  pixelformat;
216 	DWORD dwLastError = 0;
217 
218 	glw_state.hWnd = Win_CreateWindow( width, height, fullscreen );
219     glw_state.flags = 0;
220 
221 	/*
222 	** set PFD_STEREO if necessary
223 	*/
224 	if( glw_stereo->integer ) {
225 		Com_Printf( "...attempting to use stereo\n" );
226 		pfd.dwFlags |= PFD_STEREO;
227 		glw_state.flags |= QVF_STEREO_ENABLED;
228 	}
229 
230 	/*
231 	** figure out if we're running on a minidriver or not
232 	*/
233 	if( !strstr( glw_driver->string, "opengl32" ) ) {
234 		Com_Printf( "...running a minidriver: %s\n", glw_driver->string );
235 		glw_state.flags |= QVF_MINIDRIVER;
236 	}
237 
238 	/*
239 	** Load OpenGL library
240 	*/
241 	Com_Printf( "...initializing WGL: " );
242 	if( !WGL_Init( glw_driver->string ) ) {
243 		dwLastError = GetLastError();
244 		Com_Printf( "failed\n" );
245 		goto fail;
246 	}
247 	Com_Printf( "ok\n" );
248 
249 	/*
250 	** Get a DC for the specified window
251 	*/
252 	Com_Printf( "...getting DC: " );
253     if( ( glw_state.hDC = GetDC( glw_state.hWnd ) ) == NULL ) {
254 		dwLastError = GetLastError();
255 		Com_Printf( "failed\n" );
256 		goto fail;
257 	}
258 	Com_Printf( "ok\n" );
259 
260 	Com_Printf( "...setting pixel format: " );
261 	if( glw_state.flags & QVF_MINIDRIVER ) {
262 		if ( !( pixelformat = qwglChoosePixelFormat( glw_state.hDC, &pfd ) ) ) {
263 			dwLastError = GetLastError();
264 			Com_Printf( "failed\n" );
265 			goto fail;
266 		}
267 
268 		if( qwglSetPixelFormat( glw_state.hDC, pixelformat, &pfd ) == FALSE ) {
269 			dwLastError = GetLastError();
270 			Com_Printf( "failed\n" );
271 			goto fail;
272 		}
273 
274 		qwglDescribePixelFormat( glw_state.hDC, pixelformat,
275                 sizeof( pfd ), &pfd );
276 	} else {
277 		if( ( pixelformat = ChoosePixelFormat( glw_state.hDC, &pfd ) ) == 0 ) {
278 			dwLastError = GetLastError();
279 			Com_Printf( "failed\n" );
280 			goto fail;
281 		}
282 
283 		if( SetPixelFormat( glw_state.hDC, pixelformat, &pfd ) == FALSE ) {
284 			dwLastError = GetLastError();
285 			Com_Printf( "failed\n" );
286 			goto fail;
287 		}
288 
289 		DescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd );
290 
291 		if( ( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) ||
292                 glw_allow_software->integer )
293         {
294 			glw_state.flags |= QVF_ACCELERATED;
295 		}
296 	}
297 	Com_Printf( "ok\n" );
298 
299 	/*
300 	** report if stereo is desired but unavailable
301 	*/
302 	if( !( pfd.dwFlags & PFD_STEREO ) &&
303             ( glw_state.flags & QVF_STEREO_ENABLED ) )
304     {
305 		Com_Printf( "...failed to select stereo pixel format\n" );
306 		Cvar_SetInteger( "cl_stereo", 0 );
307 		glw_state.flags &= ~QVF_STEREO_ENABLED;
308 	}
309 
310 	/*
311 	** startup the OpenGL subsystem by creating a context and making
312 	** it current
313 	*/
314 	Com_Printf( "...creating OpenGL context: " );
315 	if( ( glw_state.hGLRC = qwglCreateContext( glw_state.hDC ) ) == NULL ) {
316 		dwLastError = GetLastError();
317 		Com_Printf( "failed\n" );
318 		goto fail;
319 	}
320 	Com_Printf( "ok\n" );
321 
322 	Com_Printf( "...making context current: " );
323     if( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) ) {
324 		dwLastError = GetLastError();
325 		Com_Printf( "failed\n" );
326 		goto fail;
327 	}
328 	Com_Printf( "ok\n" );
329 
330 	if( !GLimp_VerifyDriver() ) {
331 		Com_Printf( "No hardware acceleration detected\n" );
332 		goto fail;
333 	}
334 
335 	/*
336 	** print out PFD specifics
337 	*/
338 	Com_Printf( "GL_VENDOR: %s\n", qglGetString( GL_VENDOR ) );
339 	Com_Printf( "GL_RENDERER: %s\n", qglGetString( GL_RENDERER ) );
340 	Com_Printf( "GL_PFD: color(%d-bits: %d,%d,%d,%d) Z(%d-bit) stencil(%d-bit)\n",
341 		pfd.cColorBits, pfd.cRedBits, pfd.cGreenBits, pfd.cBlueBits,
342 		pfd.cAlphaBits, pfd.cDepthBits, pfd.cStencilBits );
343 
344 
345 	if( GetDeviceGammaRamp( glw_state.hDC, glw_state.originalGammaRamp ) ) {
346 		glw_state.flags |= QVF_GAMMARAMP_ENABLED;
347 		memcpy( glw_state.customGammaRamp, glw_state.originalGammaRamp,
348 			sizeof( glw_state.customGammaRamp ) );
349 	}
350 
351 	return qtrue;
352 
353 fail:
354     if( dwLastError ) {
355     	Com_Printf( "GetLastError() = 0x%lx\n", dwLastError );
356     }
357 
358 	if( glw_state.hWnd ) {
359 		Win_DestroyWindow( glw_state.hWnd );
360 		glw_state.hWnd = NULL;
361 	}
362 
363 	if( glw_state.hGLRC && qwglDeleteContext ) {
364 		qwglDeleteContext( glw_state.hGLRC );
365 		glw_state.hGLRC = NULL;
366 	}
367 
368 	if( glw_state.hDC ) {
369 		ReleaseDC( glw_state.hWnd, glw_state.hDC );
370 		glw_state.hDC = NULL;
371 	}
372 
373 	WGL_Shutdown();
374 
375 	return qfalse;
376 }
377 
378 /*
379 ** GLimp_SetMode
380 */
381 
382 // get the list of acceptable video modes
383 #include "vid_modes.h"
384 
GLimp_SetMode(int * pwidth,int * pheight,int mode,qboolean fullscreen)385 static vidSetModeResult_t GLimp_SetMode( int *pwidth, int *pheight,
386         int mode, qboolean fullscreen )
387 {
388 	int width, height;
389 	const char *win_fs[] = { "W", "FS" };
390 	DEVMODE dm;
391     qboolean success;
392 
393 	Com_Printf( "Initializing OpenGL display\n" );
394 
395 	if( mode == -1 ) {
396 		Com_Printf( "...setting custom mode: " );
397 		width = *pwidth;
398 		height = *pheight;
399 	} else {
400 		Com_Printf( "...setting mode %d: ", mode );
401 		if( !VID_GetModeInfo( &width, &height, mode ) ) {
402 			Com_Printf( "invalid mode\n" );
403 			return SETMODE_ERROR;
404 		}
405 		*pwidth = width;
406 		*pheight = height;
407 	}
408 
409 	Com_Printf( "%d %d %s\n", width, height, win_fs[fullscreen] );
410 
411 	// destroy the existing window
412 	if( glw_state.hWnd ) {
413 		GLimp_Shutdown();
414 	}
415 
416 	if( !fullscreen ) {
417 		Com_Printf( "...setting windowed mode\n" );
418         goto windowed;
419 	}
420 
421 // do a CDS if needed
422 	Com_Printf( "...attempting fullscreen\n" );
423 
424 	if( glw_bitdepth->integer && !glw_state.allowdisplaydepthchange ) {
425 		Com_Printf( "gl_bitdepth requires Win95 OSR2.x or WinNT 4.x\n" );
426 		Cvar_SetInteger( "gl_bitdepth", 0 );
427 	}
428 
429 	memset( &dm, 0, sizeof( dm ) );
430 
431 	dm.dmSize = sizeof( dm );
432 
433 	dm.dmPelsWidth  = width;
434 	dm.dmPelsHeight = height;
435 	dm.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT;
436 
437 	if( vid_displayfrequency->integer ) {
438 		dm.dmDisplayFrequency = vid_displayfrequency->integer;
439 		dm.dmFields |= DM_DISPLAYFREQUENCY;
440 		Com_Printf( "...using display frequency of %d\n",
441 			vid_displayfrequency->integer );
442 	}
443 
444 	if( glw_bitdepth->integer ) {
445 		dm.dmBitsPerPel = glw_bitdepth->integer;
446 		dm.dmFields |= DM_BITSPERPEL;
447 		Com_Printf( "...using gl_bitdepth of %d\n",
448 			glw_bitdepth->integer );
449 	} else {
450 		HDC hdc;
451 		int bitspixel;
452 
453 		hdc = GetDC( NULL );
454 		bitspixel = GetDeviceCaps( hdc, BITSPIXEL );
455 		ReleaseDC( NULL, hdc );
456 
457 		Com_Printf( "...using desktop display depth of %d\n", bitspixel );
458 	}
459 
460 	Com_Printf( "...calling CDS: " );
461 	if( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL ) {
462 		Com_Printf( "ok\n" );
463 
464         success = GLimp_InitGL( width, height, qtrue );
465         if( !success && ( glw_state.flags & QVF_MINIDRIVER ) ) {
466             Com_Printf( "...attempting to load opengl32\n" );
467             Cvar_Set( "gl_driver","opengl32" );
468             success = GLimp_InitGL( width, height, qtrue );
469         }
470 		if( !success ) {
471 			return SETMODE_ERROR;
472 		}
473 
474 		glw_state.flags |= QVF_FULLSCREEN_ENABLED;
475 		glw_state.fullscreenDM = dm;
476 		return SETMODE_FULLSCREEN;
477 	}
478 	Com_Printf( "failed\n" );
479 
480 	dm.dmPelsWidth = width * 2;
481 	dm.dmPelsHeight = height;
482 	dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
483 
484 	if( vid_displayfrequency->integer ) {
485 		dm.dmDisplayFrequency = vid_displayfrequency->integer;
486 		dm.dmFields |= DM_DISPLAYFREQUENCY;
487 	}
488 
489 	if( glw_bitdepth->integer ) {
490 		dm.dmBitsPerPel = glw_bitdepth->integer;
491 		dm.dmFields |= DM_BITSPERPEL;
492 	}
493 
494 	Com_Printf( "...calling CDS assuming dual monitors: " );
495 	if( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL ) {
496 		Com_Printf( "ok\n" );
497 
498         success = GLimp_InitGL( width, height, qtrue );
499         if( !success && ( glw_state.flags & QVF_MINIDRIVER ) ) {
500             Com_Printf( "...attempting to load opengl32\n" );
501             Cvar_Set( "gl_driver","opengl32" );
502             success = GLimp_InitGL( width, height, qtrue );
503         }
504 		if( !success ) {
505 			return SETMODE_ERROR;
506 		}
507 
508 		glw_state.flags |= QVF_FULLSCREEN_ENABLED;
509 		glw_state.fullscreenDM = dm;
510 		return SETMODE_FULLSCREEN;
511 	}
512 	Com_Printf( "failed\n" );
513 
514 	Com_Printf( "...falling back to windowed mode\n" );
515 
516 windowed:
517     ChangeDisplaySettings( NULL, 0 );
518 
519     success = GLimp_InitGL( width, height, qfalse );
520     if( !success && ( glw_state.flags & QVF_MINIDRIVER ) ) {
521         Com_Printf( "...attempting to load opengl32\n" );
522         Cvar_Set( "gl_driver","opengl32" );
523         success = GLimp_InitGL( width, height, qfalse );
524     }
525 
526     return success ? SETMODE_WINDOWED : SETMODE_ERROR;
527 }
528 
529 /*
530 ==============
531 GLimp_UpdateGamma
532 ==============
533 */
GLimp_UpdateGamma(const byte * table)534 static void GLimp_UpdateGamma( const byte *table ) {
535 	WORD v;
536 	int i;
537 
538 	if( !( glw_state.flags & QVF_GAMMARAMP_ENABLED ) ) {
539 		return;
540 	}
541 
542 	for( i = 0; i < 256; i++ ) {
543 		v = table[i] << 8;
544 		glw_state.customGammaRamp[0][i] = v;
545 		glw_state.customGammaRamp[1][i] = v;
546 		glw_state.customGammaRamp[2][i] = v;
547 	}
548 
549 	SetDeviceGammaRamp( glw_state.hDC, glw_state.customGammaRamp );
550 
551 }
552 
553 /*
554 ** GLimp_BeginFrame
555 */
GLimp_BeginFrame(float camera_separation)556 static void GLimp_BeginFrame( float camera_separation ) {
557 	//qglDrawBuffer( GL_BACK );
558 }
559 
560 /*
561 ** GLimp_EndFrame
562 **
563 ** Responsible for doing a swapbuffers and possibly for other stuff
564 ** as yet to be determined.  Probably better not to make this a GLimp
565 ** function and instead do a call to GLimp_SwapBuffers.
566 */
567 
GLimp_EndFrame(void)568 static void GLimp_EndFrame( void ) {
569 	/*if( Q_stricmp( glw_drawbuffer->string, "GL_BACK" ) == 0 ) {
570 		if( !qwglSwapBuffers( glw_state.hDC ) )
571 			Com_Error( ERR_FATAL, "GLimp_EndFrame: wglSwapBuffers failed" );
572 	}
573 	*/
574 		if( !qwglSwapBuffers( glw_state.hDC ) )
575 			Com_Error( ERR_FATAL, "GLimp_EndFrame: wglSwapBuffers failed" );
576 }
577 
578 /*
579 ============
580 GLimp_GetFlags
581 ============
582 */
GLimp_GetFlags(void)583 static vidFlags_t GLimp_GetFlags( void ) {
584 	return glw_state.flags;
585 }
586 
GLimp_AppActivate(qboolean active)587 void GLimp_AppActivate( qboolean active ) {
588 	if( !glw_state.hDC ) {
589 		return;
590 	}
591 	if( glw_state.flags & QVF_GAMMARAMP_ENABLED ) {
592 		if( active ) {
593 			SetDeviceGammaRamp( glw_state.hDC, glw_state.customGammaRamp );
594 		} else {
595 			SetDeviceGammaRamp( glw_state.hDC, glw_state.originalGammaRamp );
596 		}
597 	}
598 
599 	if( !( glw_state.flags & QVF_FULLSCREEN_ENABLED ) ) {
600 		return;
601 	}
602 	if( !vid_flip_on_switch->integer ) {
603 		return;
604 	}
605 	if( active ) {
606 		ChangeDisplaySettings( &glw_state.fullscreenDM, CDS_FULLSCREEN );
607 	} else {
608 		ChangeDisplaySettings( NULL, 0 );
609 	}
610 
611 }
612 
613 /*
614 @@@@@@@@@@@@
615 GLimp_FillAPI
616 @@@@@@@@@@@@
617 */
Video_FillGLAPI(vidGLAPI_t * api)618 void Video_FillGLAPI( vidGLAPI_t *api ) {
619 	api->Init = GLimp_Init;
620 	api->Shutdown = GLimp_Shutdown;
621 	api->UpdateGamma = GLimp_UpdateGamma;
622 	api->GetFlags = GLimp_GetFlags;
623 	api->SetMode = GLimp_SetMode;
624 	api->GetProcAddr = WGL_GetProcAddress;
625 	api->BeginFrame = GLimp_BeginFrame;
626 	api->EndFrame = GLimp_EndFrame;
627 }
628 
629