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 #include <float.h>
34 #include <windows.h>
35 #include "../ref_gl/gl_local.h"
36 #include "glw_win.h"
37 #include "winquake.h"
38 #include "wglext.h"
39 
40 //static qboolean GLimp_SwitchFullscreen( int width, int height );
41 qboolean GLimp_InitGL (void);
42 
43 glwstate_t glw_state;
44 
45 extern cvar_t *vid_fullscreen;
46 extern cvar_t *vid_ref;
47 extern cvar_t *vid_forcedrefresh;
48 extern cvar_t *vid_optimalrefresh;
49 extern cvar_t *vid_nowgl;
50 
51 DEVMODE		originalDesktopMode;
52 DEVMODE		fullScreenMode;
53 
54 qboolean	usingDesktopSettings;
55 
VerifyDriver(void)56 static qboolean VerifyDriver( void )
57 {
58 	char buffer[1024];
59 
60 	Q_strncpy( buffer, qglGetString( GL_RENDERER ), sizeof(buffer)-1);
61 	strlwr( buffer );
62 	if ( strcmp( buffer, "gdi generic" ) == 0 )
63 	{
64 		if ( !glw_state.mcd_accelerated )
65 			return false;
66 	}
67 	return true;
68 }
69 
DllMain(HINSTANCE hDll,DWORD dwReason,LPVOID lpReserved)70 BOOL WINAPI DllMain(HINSTANCE hDll,DWORD dwReason,LPVOID lpReserved)
71 {
72 	switch (dwReason)
73 	{
74 		case DLL_PROCESS_ATTACH:
75 			DisableThreadLibraryCalls (hDll);
76 			glw_state.hModule = hDll;
77 			break;
78 	}
79 
80 	return TRUE;
81 }
82 
83 /*
84 ** VID_CreateWindow
85 */
86 #define	WINDOW_CLASS_NAME	"Quake 2"
87 char	OPENGL_CLASS[32];
88 
89 static qboolean		window_class_registered = false;
90 
91 qboolean init_regular (void);
VID_CreateWindow(int width,int height,qboolean fullscreen)92 int VID_CreateWindow( int width, int height, qboolean fullscreen )
93 {
94 	WNDCLASS		wc;
95 	RECT			r;
96 	cvar_t			*vid_xpos, *vid_ypos;
97 	int				stylebits;
98 	int				x, y, w, h;
99 	int				exstyle;
100 	int				error;
101 
102 	if (!window_class_registered)
103 	{
104 		ri.Con_Printf (PRINT_DEVELOPER, "window class is not registered\n");
105 		if (GetClassInfo (glw_state.hInstance, WINDOW_CLASS_NAME, &wc))
106 		{
107 			ri.Con_Printf (PRINT_DEVELOPER, "q2 window class already exists, unregistering: ");
108 			UnregisterClass (WINDOW_CLASS_NAME, wc.hInstance);
109 			ri.Con_Printf (PRINT_DEVELOPER, "ok\n");
110 		}
111 
112 		/* Register the frame class */
113 		wc.style         = 0;
114 		wc.lpfnWndProc   = (WNDPROC)glw_state.wndproc;
115 		wc.cbClsExtra    = 0;
116 		wc.cbWndExtra    = 0;
117 		wc.hInstance     = glw_state.hInstance;
118 		wc.hIcon         = 0;
119 		wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
120 		wc.hbrBackground = (HBRUSH)COLOR_GRAYTEXT;
121 		wc.lpszMenuName  = 0;
122 		wc.lpszClassName = WINDOW_CLASS_NAME;
123 
124 		ri.Con_Printf (PRINT_DEVELOPER, "registering q2 window class: ");
125 		if (!RegisterClass (&wc))
126 		{
127 			char	*noglMsg = "";
128 			char	*msg;
129 
130 			ri.Con_Printf (PRINT_DEVELOPER, "failed\n");
131 
132 			FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&msg, 0, NULL);
133 
134 			if (Q_strncasecmp (gl_driver->string, "opengl32", 8))
135 				noglMsg = va ("\r\n\r\nYou may be getting this message because your gl_driver is set to '%s'. Try adding 'set gl_driver \"opengl32\"' to your baseq2/r1gl.cfg if problems persist.", gl_driver->string);
136 
137 			ri.Sys_Error (ERR_FATAL, "R1GL: Couldn't register window class: %s\r\n\r\nPlease make sure you have installed the latest drivers for your video card.%s", msg, noglMsg);
138 		}
139 		else
140 			ri.Con_Printf (PRINT_DEVELOPER, "ok\n");
141 
142 		window_class_registered = true;
143 	}
144 
145 	if (fullscreen)
146 	{
147 		exstyle = (FLOAT_NE_ZERO(vid_topmost->value) ? WS_EX_TOPMOST : 0);
148 		stylebits = WS_POPUP|WS_VISIBLE;
149 	}
150 	else
151 	{
152 		exstyle = 0;
153 		stylebits = WINDOW_STYLE|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
154 	}
155 
156 	r.left = 0;
157 	r.top = 0;
158 	r.right  = width;
159 	r.bottom = height;
160 
161 	AdjustWindowRect (&r, stylebits, FALSE);
162 
163 	w = r.right - r.left;
164 	h = r.bottom - r.top;
165 
166 	if (fullscreen)
167 	{
168 		x = 0;
169 		y = 0;
170 	}
171 	else
172 	{
173 		vid_xpos = ri.Cvar_Get ("vid_xpos", "0", 0);
174 		vid_ypos = ri.Cvar_Get ("vid_ypos", "0", 0);
175 		x = Q_ftol(vid_xpos->value);
176 		y = Q_ftol(vid_ypos->value);
177 	}
178 
179 	glw_state.hWnd = CreateWindowEx (
180 		 exstyle,
181 		 WINDOW_CLASS_NAME,
182 		 "Quake 2",
183 		 stylebits,
184 		 x, y, w, h,
185 		 NULL,
186 		 NULL,
187 		 glw_state.hInstance,
188 		 NULL);
189 
190 	if (!glw_state.hWnd)
191 		ri.Sys_Error (ERR_FATAL, "Couldn't create window: %d", GetLastError());
192 
193 	ShowWindow( glw_state.hWnd, SW_SHOW );
194 	UpdateWindow( glw_state.hWnd );
195 
196 	// init all the gl stuff for the window
197 	error = GLimp_InitGL ();
198 
199 	if (error != VID_ERR_NONE)
200 	{
201 		if (error & VID_ERR_RETRY_QGL)
202 			return error;
203 
204 		error = init_regular ();
205 		if (error != VID_ERR_NONE)
206 		{
207 			ri.Con_Printf( PRINT_ALL, "VID_CreateWindow() - GLimp_InitGL failed\n");
208 			return error;
209 		}
210 	}
211 
212 	SetForegroundWindow( glw_state.hWnd );
213 	SetFocus( glw_state.hWnd );
214 
215 	//r1: hudscaling
216 	width = (int)ceilf((float)width / gl_hudscale->value);
217 	height = (int)ceilf((float)height / gl_hudscale->value);
218 
219 	//round to power of 8/2 to avoid blackbars
220 	width = (width+7)&~7;
221 	height = (height+1)&~1;
222 
223 	// let the sound and input subsystems know about the new window
224 	ri.Vid_NewWindow (width, height);
225 
226 	return VID_ERR_NONE;
227 }
228 
229 
230 /*
231 ** GLimp_SetMode
232 */
GLimp_SetMode(unsigned int * pwidth,unsigned int * pheight,int mode,qboolean fullscreen)233 int GLimp_SetMode( unsigned int *pwidth, unsigned int *pheight, int mode, qboolean fullscreen )
234 {
235 	int	error;
236 	int width, height;
237 	const char *win_fs[] = { "W", "FS" };
238 
239 	ri.Con_Printf( PRINT_ALL, "Initializing OpenGL display\n");
240 
241 	if (mode == -1)
242 	{
243 		ri.Con_Printf (PRINT_ALL, "...ignoring gl_mode, using forced width / height:");
244 	}
245 	else
246 	{
247 		ri.Con_Printf (PRINT_ALL, "...setting gl_mode %d:", mode );
248 
249 		if ( !ri.Vid_GetModeInfo( &width, &height, mode ) )
250 		{
251 			ri.Con_Printf( PRINT_ALL, " invalid gl_mode\n" );
252 			return VID_ERR_INVALID_MODE;
253 		}
254 	}
255 
256 	if (FLOAT_NE_ZERO(gl_forcewidth->value))
257 		width = (int)gl_forcewidth->value;
258 
259 	if (FLOAT_NE_ZERO(gl_forceheight->value))
260 		height = (int)gl_forceheight->value;
261 
262 	ri.Con_Printf( PRINT_ALL, " %d %d %s\n", width, height, win_fs[fullscreen] );
263 
264 	// destroy the existing window
265 	if (glw_state.hWnd)
266 	{
267 		GLimp_Shutdown ();
268 	}
269 
270 	// do a CDS if needed
271 	if ( fullscreen )
272 	{
273 		DEVMODE dm;
274 
275 		int		index = 0;
276 		int		bestFrequency = 0;
277 		DEVMODE	settings;
278 
279 		EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &originalDesktopMode);
280 
281 		ri.Con_Printf( PRINT_ALL, "...attempting fullscreen\n" );
282 
283 		memset( &dm, 0, sizeof( dm ) );
284 
285 		dm.dmSize = sizeof( dm );
286 
287 		dm.dmPelsWidth  = width;
288 		dm.dmPelsHeight = height;
289 		dm.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT;
290 
291 		if ( FLOAT_NE_ZERO(gl_bitdepth->value) )
292 		{
293 			dm.dmBitsPerPel = Q_ftol(gl_bitdepth->value);
294 			dm.dmFields |= DM_BITSPERPEL;
295 			ri.Con_Printf( PRINT_ALL, "...using gl_bitdepth of %d\n", ( int ) gl_bitdepth->value );
296 		}
297 		else
298 		{
299 			ri.Con_Printf( PRINT_ALL, "...using desktop display depth of %d\n", originalDesktopMode.dmBitsPerPel );
300 
301 			//r1: be explicit about this just in case
302 			dm.dmFields |= DM_BITSPERPEL;
303 			dm.dmBitsPerPel = originalDesktopMode.dmBitsPerPel;
304 		}
305 
306 		memset (&settings, 0, sizeof(settings));
307 		settings.dmSize = sizeof(dm);
308 
309 		while ((EnumDisplaySettings (NULL, index, &settings)))
310 		{
311 			if (!(settings.dmFields & (DM_BITSPERPEL|DM_DISPLAYFREQUENCY|DM_PELSWIDTH|DM_PELSHEIGHT)))
312 				continue;
313 
314 			if (settings.dmBitsPerPel == dm.dmBitsPerPel &&
315 				settings.dmPelsWidth == dm.dmPelsWidth &&
316 				settings.dmPelsHeight == dm.dmPelsHeight)
317 			{
318 				if (settings.dmDisplayFrequency > bestFrequency)
319 					bestFrequency = settings.dmDisplayFrequency;
320 			}
321 			index++;
322 		}
323 
324 		//r1: if running q2 at desktop res, inherit desktop refresh rate
325 		if (originalDesktopMode.dmFields & (DM_BITSPERPEL|DM_DISPLAYFREQUENCY|DM_PELSWIDTH|DM_PELSHEIGHT) &&
326 			originalDesktopMode.dmPelsWidth == dm.dmPelsWidth &&
327 			originalDesktopMode.dmPelsHeight == dm.dmPelsHeight &&
328 			originalDesktopMode.dmBitsPerPel == dm.dmBitsPerPel)
329 		{
330 			dm.dmFields |= DM_DISPLAYFREQUENCY;
331 			dm.dmDisplayFrequency = originalDesktopMode.dmDisplayFrequency;
332 		}
333 
334 		//r1: allow refresh overriding
335 		if (originalDesktopMode.dmFields & DM_DISPLAYFREQUENCY)
336 		{
337 			if (FLOAT_NE_ZERO (vid_optimalrefresh->value))
338 			{
339 				dm.dmFields |= DM_DISPLAYFREQUENCY;
340 				dm.dmDisplayFrequency = bestFrequency;
341 			}
342 			else if (FLOAT_NE_ZERO(vid_forcedrefresh->value))
343 			{
344 				dm.dmFields |= DM_DISPLAYFREQUENCY;
345 				dm.dmDisplayFrequency = Q_ftol(vid_forcedrefresh->value);
346 			}
347 		}
348 		else
349 			ri.Con_Printf (PRINT_ALL, "...ignoring frequencies, no driver support\n");
350 
351 		ri.Con_Printf( PRINT_ALL, "...calling CDS: " );
352 		if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL )
353 		{
354 			*pwidth = width;
355 			*pheight = height;
356 
357 			gl_state.fullscreen = true;
358 
359 			ri.Con_Printf( PRINT_ALL, "ok\n" );
360 
361 			error = VID_CreateWindow (width, height, true);
362 			if (error != VID_ERR_NONE)
363 				return error;
364 
365 			ri.Con_Printf (PRINT_DEVELOPER, "Checking fullscreen frequencies: \n");
366 			EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &fullScreenMode);
367 
368 			if (originalDesktopMode.dmFields & DM_DISPLAYFREQUENCY)
369 			{
370 				if (fullScreenMode.dmDisplayFrequency < bestFrequency)
371 					ri.Con_Printf (PRINT_ALL, "\2NOTE: You are currently using a refresh rate of %d Hz. Your monitor claims to support up to %d Hz at %dx%d. Consider increasing your refresh rate for better performance by setting vid_optimalrefresh 1\n", fullScreenMode.dmDisplayFrequency, bestFrequency, fullScreenMode.dmPelsWidth, fullScreenMode.dmPelsHeight);
372 			}
373 			ri.Con_Printf (PRINT_DEVELOPER, "ok\n");
374 
375 			return VID_ERR_NONE;
376 		}
377 		else
378 		{
379 			*pwidth = width;
380 			*pheight = height;
381 
382 			ri.Con_Printf( PRINT_ALL, "failed\n" );
383 
384 			ri.Con_Printf( PRINT_ALL, "...calling CDS assuming dual monitors:" );
385 
386 			dm.dmPelsWidth = width * 2;
387 
388 			//should already still be set
389 			/*
390 			dm.dmPelsHeight = height;
391 			dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
392 
393 			if ( FLOAT_NE_ZERO(gl_bitdepth->value) )
394 			{
395 				dm.dmBitsPerPel = Q_ftol(gl_bitdepth->value);
396 				dm.dmFields |= DM_BITSPERPEL;
397 			}*/
398 
399 			/*
400 			** our first CDS failed, so maybe we're running on some weird dual monitor
401 			** system
402 			*/
403 			if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL )
404 			{
405 				ri.Con_Printf( PRINT_ALL, " failed\n" );
406 
407 				ri.Con_Printf( PRINT_ALL, "...setting windowed mode\n" );
408 
409 				ChangeDisplaySettings( 0, 0 );
410 
411 				*pwidth = width;
412 				*pheight = height;
413 				gl_state.fullscreen = false;
414 				error = VID_CreateWindow (width, height, false);
415 				if (error != VID_ERR_NONE)
416 				{
417 					error |= VID_ERR_FULLSCREEN_FAILED;
418 					return error;
419 				}
420 			}
421 			else
422 			{
423 				ri.Con_Printf( PRINT_ALL, " ok\n" );
424 				error = VID_CreateWindow (width, height, true);
425 				if (error != VID_ERR_NONE)
426 					return error;
427 
428 				EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &fullScreenMode);
429 				gl_state.fullscreen = true;
430 				return VID_ERR_NONE;
431 			}
432 		}
433 	}
434 	else
435 	{
436 		ri.Con_Printf( PRINT_ALL, "...setting windowed mode\n" );
437 
438 		ChangeDisplaySettings( 0, 0 );
439 
440 		*pwidth = width;
441 		*pheight = height;
442 		gl_state.fullscreen = false;
443 		error = VID_CreateWindow (width, height, false);
444 		if (error != VID_ERR_NONE)
445 			return error;
446 	}
447 
448 	return VID_ERR_NONE;
449 }
450 
451 /*
452 ** GLimp_Shutdown
453 **
454 ** This routine does all OS specific shutdown procedures for the OpenGL
455 ** subsystem.  Under OpenGL this means NULLing out the current DC and
456 ** HGLRC, deleting the rendering context, and releasing the DC acquired
457 ** for the window.  The state structure is also nulled out.
458 **
459 */
GLimp_Shutdown(void)460 void GLimp_Shutdown( void )
461 {
462 	WNDCLASS		wc;
463 
464 #ifdef USE_MSGLOG
465   if(hMsgLog) FreeLibrary(hMsgLog);
466 #endif
467 
468 	if ( qwglMakeCurrent && !qwglMakeCurrent( NULL, NULL ) )
469 		ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglMakeCurrent failed\n");
470 	if ( glw_state.hGLRC )
471 	{
472 		if (  qwglDeleteContext && !qwglDeleteContext( glw_state.hGLRC ) )
473 			ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglDeleteContext failed\n");
474 		glw_state.hGLRC = NULL;
475 	}
476 	if (glw_state.hDC)
477 	{
478 		if ( !ReleaseDC( glw_state.hWnd, glw_state.hDC ) )
479 			ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - ReleaseDC failed\n" );
480 		glw_state.hDC   = NULL;
481 	}
482 
483 	if (glw_state.hWnd)
484 	{
485 		ShowWindow (glw_state.hWnd, SW_HIDE);
486 		DestroyWindow (	glw_state.hWnd );
487 		glw_state.hWnd = NULL;
488 	}
489 
490 	if ( glw_state.log_fp )
491 	{
492 		fclose( glw_state.log_fp );
493 		glw_state.log_fp = 0;
494 	}
495 
496 	if (GetClassInfo (glw_state.hInstance, WINDOW_CLASS_NAME, &wc))
497 	{
498 		ri.Con_Printf (PRINT_DEVELOPER, "unregistering q2 window class: ");
499 		UnregisterClass (WINDOW_CLASS_NAME, wc.hInstance);
500 		ri.Con_Printf (PRINT_DEVELOPER, "ok\n");
501 	}
502 
503 	if (GetClassInfo (glw_state.hInstance, OPENGL_CLASS, &wc))
504 	{
505 		ri.Con_Printf (PRINT_DEVELOPER, "unregistering opengl class: ");
506 		UnregisterClass (OPENGL_CLASS, wc.hInstance);
507 		ri.Con_Printf (PRINT_DEVELOPER, "ok\n");
508 	}
509 
510 	window_class_registered = false;
511 
512 	if ( gl_state.fullscreen )
513 	{
514 		ChangeDisplaySettings( 0, 0 );
515 		gl_state.fullscreen = false;
516 	}
517 }
518 
519 
520 /*
521 ** GLimp_Init
522 **
523 ** This routine is responsible for initializing the OS specific portions
524 ** of OpenGL.  Under Win32 this means dealing with the pixelformats and
525 ** doing the wgl interface stuff.
526 */
GLimp_Init(void * hinstance,void * wndproc)527 qboolean GLimp_Init( void *hinstance, void *wndproc )
528 {
529 #define OSR2_BUILD_NUMBER 1111
530 
531 	OSVERSIONINFO	vinfo;
532 
533 	if (!OPENGL_CLASS[0])
534 		Com_sprintf (OPENGL_CLASS, sizeof(OPENGL_CLASS), "R1GLOpenGLPFD-%u", GetTickCount());
535 
536 #ifndef _M_AMD64
537 	//_controlfp( _PC_24, _MCW_PC );
538 #endif
539 
540 	vinfo.dwOSVersionInfoSize = sizeof(vinfo);
541 
542 	glw_state.allowdisplaydepthchange = false;
543 
544 	if ( GetVersionEx( &vinfo) )
545 	{
546 		if ( vinfo.dwMajorVersion > 4 )
547 		{
548 			glw_state.allowdisplaydepthchange = true;
549 		}
550 		else if ( vinfo.dwMajorVersion == 4 )
551 		{
552 			if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
553 			{
554 				glw_state.allowdisplaydepthchange = true;
555 			}
556 			else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
557 			{
558 				if ( LOWORD( vinfo.dwBuildNumber ) >= OSR2_BUILD_NUMBER )
559 				{
560 					glw_state.allowdisplaydepthchange = true;
561 				}
562 			}
563 		}
564 	}
565 	else
566 	{
567 		ri.Con_Printf( PRINT_ALL, "GLimp_Init() - GetVersionEx failed\n" );
568 		return false;
569 	}
570 
571 	glw_state.hInstance = ( HINSTANCE ) hinstance;
572 	glw_state.wndproc = wndproc;
573 
574 	return true;
575 }
576 
577 // Define entry points
578 #define WGL_SAMPLE_BUFFERS_ARB             0x2041
579 #define WGL_SAMPLES_ARB                    0x2042
580 
581 // WGL_ARB_extensions_string
582 PFNWGLGETEXTENSIONSSTRINGARBPROC     wglGetExtensionsStringARB;
583 
584 PFNWGLGETEXTENSIONSSTRINGEXTPROC     wglGetExtensionsStringEXT;
585 
586 // WGL_ARB_pixel_format
587 PFNWGLGETPIXELFORMATATTRIBIVARBPROC  wglGetPixelFormatAttribivARB;
588 PFNWGLGETPIXELFORMATATTRIBFVARBPROC  wglGetPixelFormatAttribfvARB;
589 PFNWGLCHOOSEPIXELFORMATARBPROC       wglChoosePixelFormatARB;
590 
591 qboolean _is_multisample;
592 
593 // Determine if an OpenGL extension is supported.
_glExtensionSupported(const char * extension)594 int _glExtensionSupported(const char *extension)
595 {
596     static const GLubyte *extensions = NULL;
597     const GLubyte *start;
598     GLubyte *where, *terminator;
599 
600     extensions = qglGetString(GL_EXTENSIONS);
601 
602     // Extension names should not have spaces.
603     where = (GLubyte *) strchr(extension, ' ');
604     if (where || *extension == '\0')
605         return 0;
606 
607     // It takes a bit of care to be fool-proof about parsing the
608     // OpenGL extensions string.  Don't be fooled by sub-strings,
609     // etc.
610     start = extensions;
611     for (;;)
612     {
613         where = (GLubyte *) strstr((const char *) start, extension);
614         if (!where)
615             break;
616         terminator = where + strlen(extension);
617         if (where == start || *(where - 1) == ' ')
618             if (*terminator == ' ' || *terminator == '\0')
619                 return 1;
620 
621         start = terminator;
622     }
623     return 0;
624 }
625 
626 // Determine if an OpenGL WGL extension is supported.
627 //
628 // NOTE:  This routine uses wglGetProcAddress so this routine REQUIRES
629 // that the calling thread is bound to a hardware-accelerated OpenGL
630 // rendering context.
_wglExtensionSupported(const char * extension)631 int _wglExtensionSupported(const char *extension)
632 {
633     if (wglGetExtensionsStringARB || wglGetExtensionsStringEXT)
634     {
635         static const GLubyte *extensions = NULL;
636         const GLubyte *start;
637         GLubyte *where, *terminator;
638 
639         // Extension names should not have spaces.
640         where = (GLubyte *) strchr(extension, ' ');
641         if (where || *extension == '\0')
642             return 0;
643 
644         if (!extensions)
645         {
646             HDC hdc = GetDC(0);
647             if (wglGetExtensionsStringARB)
648                 extensions = (const GLubyte *) wglGetExtensionsStringARB(hdc);
649             else
650                 extensions = (const GLubyte *) wglGetExtensionsStringEXT();
651             ReleaseDC(0, hdc);
652 			//ri.Con_Printf (PRINT_ALL, "wglExtensions: %s\n", extensions);
653         }
654 
655 		//ri.Con_Printf (PRINT_ALL, "WGL Extensions: %s\n", extensions);
656 
657         // It takes a bit of care to be fool-proof about parsing the
658         // OpenGL extensions string.  Don't be fooled by sub-strings,
659         // etc.
660         start = extensions;
661         for (;;) {
662             where = (GLubyte *) strstr((const char *) start, extension);
663             if (!where)
664                 break;
665             terminator = where + strlen(extension);
666             if (where == start || *(where - 1) == ' ')
667                 if (*terminator == ' ' || *terminator == '\0')
668                     return 1;
669 
670             start = terminator;
671         }
672     }
673     else
674 	{
675         ri.Sys_Error (ERR_FATAL, "WGL extension string not found!");
676 	}
677 
678     return 0;
679 }
680 
init_extensions()681 qboolean init_extensions()
682 {
683     if (_wglExtensionSupported("WGL_ARB_extensions_string") == 0)
684     {
685         if (_glExtensionSupported("WGL_EXT_extensions_string") == 0)
686         {
687             ri.Con_Printf (PRINT_ALL, "init_extensions: Neither WGL_ARB_extensions_string nor WGL_EXT_extensions_string found!");
688             return false;
689         }
690     }
691 
692     if (_wglExtensionSupported("WGL_ARB_multisample") && gl_ext_multisample->value)
693     {
694         _is_multisample = true;
695     }
696     else
697     {
698 		if (FLOAT_NE_ZERO(gl_ext_multisample->value))
699 			ri.Con_Printf (PRINT_ALL, "WGL_ARB_multisample not found.\n");
700 		ri.Cvar_Set ("gl_ext_multisample", "0");
701         _is_multisample = false;
702     }
703 
704     if (_wglExtensionSupported("WGL_ARB_pixel_format"))
705 	{
706         wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)qwglGetProcAddress("wglGetPixelFormatAttribivARB");
707         wglGetPixelFormatAttribfvARB = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)qwglGetProcAddress("wglGetPixelFormatAttribfvARB");
708         wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)qwglGetProcAddress("wglChoosePixelFormatARB");
709 	}
710 	else
711     {
712 		ri.Con_Printf (PRINT_ALL, "init_extensions: WGL_ARB_pixel_format not found!");
713         return false;
714     }
715 
716     return true;
717 }
718 
719 // don't do anything
StupidOpenGLProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)720 static LRESULT CALLBACK StupidOpenGLProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
721 {
722   return DefWindowProc(hWnd,msg,wParam,lParam);
723 }
724 
725 // Registers the window classes
RegisterOpenGLWindow(HINSTANCE hInst)726 BOOL RegisterOpenGLWindow(HINSTANCE hInst)
727 {
728 	WNDCLASSEX wcex;
729 
730 	// Initialize our Window class
731 	wcex.cbSize = sizeof(wcex);
732 
733 	if (GetClassInfoEx (hInst, OPENGL_CLASS, &wcex))
734 	{
735 		ri.Con_Printf (PRINT_DEVELOPER, "opengl class already exists, unregistering: ");
736 		UnregisterClass (OPENGL_CLASS, wcex.hInstance);
737 		ri.Con_Printf (PRINT_DEVELOPER, "ok\n");
738 	}
739 
740 	// register main one
741 	ZeroMemory(&wcex,sizeof(wcex));
742 
743 	// now the stupid one
744 	wcex.cbSize			= sizeof(wcex);
745 	wcex.style			= CS_OWNDC;
746 	wcex.cbWndExtra		= 0; /* space for our pointer */
747 	//wcex.lpfnWndProc	= StupidOpenGLProc;
748 	wcex.lpfnWndProc	= DefWindowProc;
749 	wcex.hbrBackground	= NULL;
750 	wcex.hInstance		= hInst;
751 	wcex.hCursor		= LoadCursor(NULL,IDC_ARROW);
752 	wcex.lpszClassName	= OPENGL_CLASS;
753 
754 	ri.Con_Printf (PRINT_DEVELOPER, "registering opengl window class: ");
755 	if (!RegisterClassEx (&wcex))
756 	{
757 		ri.Con_Printf (PRINT_DEVELOPER, "failed\n");
758 		ri.Sys_Error (ERR_FATAL, "R1GL: Unable to register OpenGL window (%d).\r\n\r\nTry adding 'set vid_nowgl 1' to your baseq2/r1gl.cfg", GetLastError());
759 		return FALSE;
760 	}
761 
762 	ri.Con_Printf (PRINT_DEVELOPER, "ok\n");
763 
764 	return TRUE;
765 }
766 
init_regular(void)767 qboolean init_regular (void)
768 {
769     PIXELFORMATDESCRIPTOR pfd =
770 	{
771 		sizeof(PIXELFORMATDESCRIPTOR),	// size of this pfd
772 		1,								// version number
773 		PFD_DRAW_TO_WINDOW |			// support window
774 		PFD_SUPPORT_OPENGL |			// support OpenGL
775 		PFD_DOUBLEBUFFER,				// double buffered
776 		PFD_TYPE_RGBA,					// RGBA type
777 		24,								// 24-bit color depth
778 		0, 0, 0, 0, 0, 0,				// color bits ignored
779 		0,								// no alpha buffer
780 		0,								// shift bit ignored
781 		0,								// no accumulation buffer
782 		0, 0, 0, 0, 					// accum bits ignored
783 		32,								// 32-bit z-buffer
784 		0,								// no stencil buffer
785 		0,								// no auxiliary buffer
786 		PFD_MAIN_PLANE,					// main layer
787 		0,								// reserved
788 		0, 0, 0							// layer masks ignored
789     };
790     int  pixelformat;
791 
792 #ifdef STEREO_SUPPORT
793 	cvar_t *stereo;
794 
795 	stereo = ri.Cvar_Get( "cl_stereo", "0", 0 );
796 
797 	/*
798 	** set PFD_STEREO if necessary
799 	*/
800 	if ( FLOAT_NE_ZERO(stereo->value))
801 	{
802 		ri.Con_Printf( PRINT_ALL, "...attempting to use stereo\n" );
803 		pfd.dwFlags |= PFD_STEREO;
804 		gl_state.stereo_enabled = true;
805 	}
806 	else
807 	{
808 		gl_state.stereo_enabled = false;
809 	}
810 #endif
811 
812 	/*
813 	** figure out if we're running on a minidriver or not
814 	*/
815 	if ( strstr( gl_driver->string, "opengl32" ) != 0 )
816 		glw_state.minidriver = false;
817 	else
818 		glw_state.minidriver = true;
819 
820 	/*
821 	** Get a DC for the specified window
822 	*/
823 	if ( glw_state.hDC != NULL )
824 		ri.Con_Printf( PRINT_ALL, "GLimp_Init() - non-NULL DC exists\n" );
825 
826     if ( ( glw_state.hDC = GetDC( glw_state.hWnd ) ) == NULL )
827 	{
828 		ri.Con_Printf( PRINT_ALL, "GLimp_Init() - GetDC failed\n" );
829 		return VID_ERR_FAIL;
830 	}
831 
832 	if ( glw_state.minidriver )
833 	{
834 		if ( (pixelformat = qwglChoosePixelFormat( glw_state.hDC, &pfd)) == 0 )
835 		{
836 			ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglChoosePixelFormat failed\n");
837 			return VID_ERR_FAIL;
838 		}
839 		if ( qwglSetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE )
840 		{
841 			ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglSetPixelFormat failed\n");
842 			return VID_ERR_FAIL;
843 		}
844 		qwglDescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd );
845 	}
846 	else
847 	{
848 		if ( ( pixelformat = ChoosePixelFormat( glw_state.hDC, &pfd)) == 0 )
849 		{
850 			ri.Con_Printf (PRINT_ALL, "GLimp_Init() - ChoosePixelFormat failed\n");
851 			return VID_ERR_FAIL;
852 		}
853 		if ( SetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE )
854 		{
855 			ri.Con_Printf (PRINT_ALL, "GLimp_Init() - SetPixelFormat failed\n");
856 			return VID_ERR_FAIL;
857 		}
858 		DescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd );
859 
860 		if ( !( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) )
861 		{
862 			extern cvar_t *gl_allow_software;
863 
864 			if ( FLOAT_NE_ZERO(gl_allow_software->value) )
865 				glw_state.mcd_accelerated = true;
866 			else
867 				glw_state.mcd_accelerated = false;
868 		}
869 		else
870 		{
871 			glw_state.mcd_accelerated = true;
872 		}
873 	}
874 
875 #ifdef STEREO_SUPPORT
876 	/*
877 	** report if stereo is desired but unavailable
878 	*/
879 	if ( !( pfd.dwFlags & PFD_STEREO ) && ( FLOAT_NE_ZERO(stereo->value)) )
880 	{
881 		ri.Con_Printf( PRINT_ALL, "...failed to select stereo pixel format\n" );
882 		ri.Cvar_SetValue( "cl_stereo", 0 );
883 		gl_state.stereo_enabled = false;
884 	}
885 #endif
886 
887 	/*
888 	** startup the OpenGL subsystem by creating a context and making
889 	** it current
890 	*/
891 	if ( ( glw_state.hGLRC = qwglCreateContext( glw_state.hDC ) ) == 0 )
892 	{
893 		ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglCreateContext failed\n");
894 
895 		goto fail;
896 	}
897 
898     if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) )
899 	{
900 		ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglMakeCurrent failed\n");
901 
902 		goto fail;
903 	}
904 
905 	if ( !VerifyDriver() )
906 	{
907 		const char *extraMsg;
908 
909 		ri.Con_Printf( PRINT_ALL, "GLimp_Init() - no hardware acceleration detected\n" );
910 
911 		if (strcmp (gl_driver->string, "opengl32"))
912 		{
913 			ri.Con_Printf( PRINT_ALL, "GLimp_Init() - trying again with gl_driver 'opengl32'\n" );
914 			ri.Cvar_Set ("gl_driver", "opengl32");
915 
916 			if ( glw_state.hGLRC )
917 			{
918 				qwglDeleteContext( glw_state.hGLRC );
919 				glw_state.hGLRC = NULL;
920 			}
921 
922 			if ( glw_state.hDC )
923 			{
924 				ReleaseDC( glw_state.hWnd, glw_state.hDC );
925 				glw_state.hDC = NULL;
926 			}
927 
928 			return VID_ERR_RETRY_QGL;
929 		}
930 
931 		if (GetFileAttributes("opengl32.dll") != -1)
932 			extraMsg = "\r\n\r\nYou may also be getting this problem due to an invalid opengl32.dll file in your Quake II directory. Delete it and try running R1GL again.";
933 		else
934 			extraMsg = "";
935 
936 		ri.Sys_Error (ERR_FATAL, "R1GL could not setup a hardware accelerated OpenGL window.\r\n\r\nPlease check you have installed the latest drivers for your video card and that it supports OpenGL.%s", extraMsg);
937 		goto fail;
938 	}
939 
940 	/*
941 	** print out PFD specifics
942 	*/
943 	ri.Con_Printf( PRINT_ALL, "GL PFD: color(%d-bits) Z(%d-bit)\n", ( int ) pfd.cColorBits, ( int ) pfd.cDepthBits );
944 
945 	return VID_ERR_NONE;
946 
947 fail:
948 	if ( glw_state.hGLRC )
949 	{
950 		qwglDeleteContext( glw_state.hGLRC );
951 		glw_state.hGLRC = NULL;
952 	}
953 
954 	if ( glw_state.hDC )
955 	{
956 		ReleaseDC( glw_state.hWnd, glw_state.hDC );
957 		glw_state.hDC = NULL;
958 	}
959 	return VID_ERR_FAIL;
960 }
961 /*
962 qboolean init_regular (void)
963 {
964     PIXELFORMATDESCRIPTOR pfd =
965 	{
966 		sizeof(PIXELFORMATDESCRIPTOR),	// size of this pfd
967 		1,								// version number
968 		PFD_DRAW_TO_WINDOW |			// support window
969 		PFD_SUPPORT_OPENGL |			// support OpenGL
970 		PFD_GENERIC_ACCELERATED |		// accelerated
971 		PFD_DOUBLEBUFFER,				// double buffered
972 		PFD_TYPE_RGBA,					// RGBA type
973 		24,								// 24-bit color depth
974 		0, 0, 0, 0, 0, 0,				// color bits ignored
975 		0,								// no alpha buffer
976 		0,								// shift bit ignored
977 		0,								// no accumulation buffer
978 		0, 0, 0, 0, 					// accum bits ignored
979 		32,								// 32-bit z-buffer
980 		0,								// no stencil buffer
981 		0,								// no auxiliary buffer
982 		PFD_MAIN_PLANE,					// main layer
983 		0,								// reserved
984 		0, 0, 0							// layer masks ignored
985     };
986 
987     int  pixelformat;
988 
989 	if ( ( glw_state.hDC = GetDC( glw_state.hWnd ) ) == NULL )
990 	{
991 		ri.Con_Printf( PRINT_ALL, "�����������̨������� GetDC failed\n" );
992 		return false;
993 	}
994 
995 	if ( ( pixelformat = ChoosePixelFormat( glw_state.hDC, &pfd)) == 0 )
996 	{
997 		ri.Con_Printf (PRINT_ALL, "�����������̨������� ChoosePixelFormat failed\n");
998 		return false;
999 	}
1000 
1001 	if ( SetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE )
1002 	{
1003 		ri.Con_Printf (PRINT_ALL, "�����������̨������� SetPixelFormat failed\n");
1004 		return false;
1005 	}
1006 
1007 	DescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd );
1008 
1009 	if ( !( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) )
1010 	{
1011 		extern cvar_t *gl_allow_software;
1012 
1013 		if ( gl_allow_software->value )
1014 			glw_state.mcd_accelerated = true;
1015 		else
1016 			glw_state.mcd_accelerated = false;
1017 	}
1018 	else
1019 	{
1020 		glw_state.mcd_accelerated = true;
1021 	}
1022 
1023 #ifdef STEREO_SUPPORT
1024 	if ( !( pfd.dwFlags & PFD_STEREO ) && ( stereo->value != 0 ) )
1025 	{
1026 		ri.Con_Printf( PRINT_ALL, "...failed to select stereo pixel format\n" );
1027 		ri.Cvar_SetValue( "cl_stereo", 0 );
1028 		gl_state.stereo_enabled = false;
1029 	}
1030 #endif
1031 
1032 	if ( ( glw_state.hGLRC = qwglCreateContext( glw_state.hDC ) ) == 0 )
1033 	{
1034 		ri.Con_Printf (PRINT_ALL, "�����������̨������� qwglCreateContext failed\n");
1035 
1036 		goto fail;
1037 	}
1038 
1039 	if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) )
1040 	{
1041 		ri.Con_Printf (PRINT_ALL, "�����������̨������� qwglMakeCurrent failed\n");
1042 
1043 		goto fail;
1044 	}
1045 
1046 	return true;
1047 
1048 fail:
1049 	if ( glw_state.hGLRC )
1050 	{
1051 		qwglDeleteContext( glw_state.hGLRC );
1052 		glw_state.hGLRC = NULL;
1053 	}
1054 
1055 	if ( glw_state.hDC )
1056 	{
1057 		ReleaseDC( glw_state.hWnd, glw_state.hDC );
1058 		glw_state.hDC = NULL;
1059 	}
1060 	return false;
1061 }*/
1062 
GLimp_InitGL(void)1063 qboolean GLimp_InitGL (void)
1064 {
1065 	HGLRC	hGLRC;
1066 	HWND	temphwnd;
1067 	HDC		hDC;
1068 
1069     /*PIXELFORMATDESCRIPTOR pfd =
1070 	{
1071 		sizeof(PIXELFORMATDESCRIPTOR),	// size of this pfd
1072 		1,								// version number
1073 		PFD_DRAW_TO_WINDOW |			// support window
1074 		PFD_SUPPORT_OPENGL |			// support OpenGL
1075 		PFD_GENERIC_ACCELERATED |		// accelerated
1076 		PFD_DOUBLEBUFFER,				// double buffered
1077 		PFD_TYPE_RGBA,					// RGBA type
1078 		24,								// 24-bit color depth
1079 		0, 0, 0, 0, 0, 0,				// color bits ignored
1080 		0,								// no alpha buffer
1081 		0,								// shift bit ignored
1082 		0,								// no accumulation buffer
1083 		0, 0, 0, 0, 					// accum bits ignored
1084 		32,								// 32-bit z-buffer
1085 		0,								// no stencil buffer
1086 		0,								// no auxiliary buffer
1087 		PFD_MAIN_PLANE,					// main layer
1088 		0,								// reserved
1089 		0, 0, 0							// layer masks ignored
1090     };
1091 
1092     int  pixelformat;*/
1093 #ifdef STEREO_SUPPORT
1094 	cvar_t *stereo;
1095 #endif
1096 
1097 #ifdef STEREO_SUPPORT
1098 	stereo = ri.Cvar_Get( "cl_stereo", "0", 0 );
1099 
1100 	/*
1101 	** set PFD_STEREO if necessary
1102 	*/
1103 	if ( FLOAT_NE_ZERO(stereo->value))
1104 	{
1105 		ri.Con_Printf( PRINT_ALL, "...attempting to use stereo\n" );
1106 		pfd.dwFlags |= PFD_STEREO;
1107 		gl_state.stereo_enabled = true;
1108 	}
1109 	else
1110 	{
1111 		gl_state.stereo_enabled = false;
1112 	}
1113 #endif
1114 
1115 	if (FLOAT_NE_ZERO(vid_nowgl->value))
1116 		return init_regular ();
1117 
1118 	glw_state.minidriver = false;
1119 
1120 	/*
1121 	** Get a DC for the specified window
1122 	*/
1123 	if ( glw_state.hDC != NULL )
1124 		ri.Con_Printf( PRINT_ALL, "�����������̨������� non-NULL DC exists\n" );
1125 
1126 	{
1127 		WORD ramps[3][256];
1128 		DEVMODE dm;
1129 		HDC hdDesk;
1130 		memset( &dm, 0, sizeof( dm ) );
1131 		hdDesk = GetDC( GetDesktopWindow() );
1132 
1133 		dm.dmSize = sizeof( dm );
1134 		dm.dmBitsPerPel = GetDeviceCaps( hdDesk, BITSPIXEL );
1135 		dm.dmFields     = DM_BITSPERPEL;
1136 
1137 		if (GetDeviceGammaRamp (hdDesk, ramps))
1138 		{
1139 			if (ramps[0][0] > 0 || ramps[1][0] > 0 || ramps[2][0] > 0)
1140 				ri.Cvar_Get ("vid_hwgamma", va ("GDGR: %d-%d-%d", ramps[0][0], ramps[1][0], ramps[2][0]), CVAR_NOSET);
1141 		}
1142 
1143 		ReleaseDC( GetDesktopWindow(), hdDesk );
1144 
1145 		if (FLOAT_LE_ZERO(gl_colorbits->value))
1146 			ri.Cvar_Set ("gl_colorbits", dm.dmBitsPerPel == 32 ? "24" : "16");
1147 
1148 		if (FLOAT_LE_ZERO(gl_depthbits->value))
1149 			ri.Cvar_Set ("gl_depthbits", dm.dmBitsPerPel == 32 ? "24" : "16");
1150 
1151 		if (!*gl_alphabits->string)
1152 			ri.Cvar_Set ("gl_alphabits", dm.dmBitsPerPel == 32 ? "8" : "0");
1153 
1154 		if (!*gl_stencilbits->string)
1155 			ri.Cvar_Set ("gl_stencilbits", dm.dmBitsPerPel == 32 ? "8" : "0");
1156 	}
1157 
1158 	if (gl_colorbits->value < 24)
1159 	{
1160 		if (FLOAT_NE_ZERO(gl_alphabits->value))
1161 		{
1162 			ri.Con_Printf (PRINT_ALL, "GLimp_InitGL() - disabling gl_alphabits with colorbits %d\n", (int)gl_colorbits->value);
1163 			ri.Cvar_Set ("gl_alphabits", "0");
1164 		}
1165 		if (FLOAT_NE_ZERO(gl_stencilbits->value))
1166 		{
1167 			ri.Con_Printf (PRINT_ALL, "GLimp_InitGL() - disabling gl_stencilbits with colorbits %d\n", (int)gl_colorbits->value);
1168 			ri.Cvar_Set ("gl_stencilbits", "0");
1169 		}
1170 	}
1171 
1172 	RegisterOpenGLWindow (glw_state.hInstance);
1173 
1174 	{
1175 		int     iAttributes[30];
1176 		float   fAttributes[] = {0, 0};
1177 		int     iResults[30];
1178 		//int     nPFD = 0;
1179 		int     pixelFormat;
1180 		unsigned int numFormats;
1181 		int		status;
1182 
1183 		PIXELFORMATDESCRIPTOR temppfd = {
1184 			sizeof(PIXELFORMATDESCRIPTOR),   // size of this pfd
1185 			1,                     // version number
1186 			PFD_DRAW_TO_WINDOW |   // support window
1187 			PFD_GENERIC_ACCELERATED | // accelerated
1188 			PFD_SUPPORT_OPENGL |   // support OpenGL
1189 			PFD_DOUBLEBUFFER,      // double buffered
1190 			PFD_TYPE_RGBA,         // RGBA type
1191 			(byte)Q_ftol(gl_colorbits->value),// desktop color depth
1192 			0, 0, 0, 0, 0, 0,      // color bits ignored
1193 			(byte)Q_ftol(gl_alphabits->value), // alpha buffer
1194 			0,                     // shift bit ignored
1195 			0,                     // no accumulation buffer
1196 			0, 0, 0, 0,            // accum bits ignored
1197 			(byte)Q_ftol(gl_depthbits->value), // z-buffer
1198 			(byte)Q_ftol(gl_stencilbits->value), // no stencil buffer
1199 			0,                     // no auxiliary buffer
1200 			PFD_MAIN_PLANE,        // main layer
1201 			0,                     // reserved
1202 			0, 0, 0                // layer masks ignored
1203 		};
1204 
1205 		temphwnd =
1206 			CreateWindowEx (
1207 				0L,OPENGL_CLASS, "R1GL OpenGL PFD Detection Window",
1208 				WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 1, 1,
1209 				glw_state.hWnd, 0, glw_state.hInstance, NULL
1210 			);
1211 
1212 		if (!temphwnd)
1213 			ri.Sys_Error (ERR_FATAL, "R1GL: Couldn't create OpenGL PFD Detection Window (%d).\r\n\r\nTry 'set vid_nowgl 1' in your baseq2/r1gl.cfg.", GetLastError());
1214 
1215 		hDC = GetDC (temphwnd);
1216 
1217 		hGLRC = NULL;
1218 
1219 		// Set up OpenGL
1220 		pixelFormat = ChoosePixelFormat(hDC, &temppfd);
1221 
1222 		if (!pixelFormat)
1223 		{
1224 			ri.Con_Printf (PRINT_ALL, "�����������̨�������ChoosePixelFormat (%dc/%dd/%da/%ds) failed. Error %.8x.\n", (int)gl_colorbits->value, (int)gl_depthbits->value, (int)gl_alphabits->value, (int)gl_stencilbits->value, GetLastError());
1225 			goto fail2;
1226 		}
1227 
1228 		if (SetPixelFormat(hDC, pixelFormat, &temppfd) == FALSE)
1229 		{
1230 			ri.Con_Printf (PRINT_ALL, "�����������̨������� SetPixelFormat (%d) failed. Error %.8x.\n", pixelFormat, GetLastError());
1231 			goto fail2;
1232 		}
1233 
1234 		// Create a rendering context
1235 		hGLRC = qwglCreateContext(hDC);
1236 		if (!hGLRC)
1237 		{
1238 			ri.Con_Printf (PRINT_ALL, "�����������̨������� qwglCreateContext failed\n");
1239 			goto fail2;
1240 		}
1241 
1242 		// Make the rendering context current
1243 		if (!(qwglMakeCurrent(hDC, hGLRC)))
1244 		{
1245 			ri.Con_Printf (PRINT_ALL, "�����������̨������� qwglMakeCurrent failed\n");
1246 			goto fail2;
1247 		}
1248 
1249 		{
1250 			const char *s;
1251 			s = qglGetString( GL_RENDERER );
1252 
1253 			if (strcmp (s, "GDI Generic") == 0)
1254 			{
1255 				ri.Con_Printf (PRINT_ALL, "�����������̨������� no hardware accelerated pixelformats matching your current settings (try editing gl_colorbits/gl_alphabits/gl_depthbits/gl_stencilbits)\n");
1256 
1257 				// make no rendering context current
1258 				qwglMakeCurrent(NULL, NULL);
1259 
1260 				// Destroy the rendering context...
1261 				qwglDeleteContext(hGLRC);
1262 				hGLRC = NULL;
1263 				ReleaseDC (temphwnd, hDC);
1264 				DestroyWindow (temphwnd);
1265 				temphwnd = NULL;
1266 
1267 				if (strcmp (gl_driver->string, "opengl32"))
1268 				{
1269 					ri.Con_Printf (PRINT_ALL, "Retrying with gl_driver opengl32\n");
1270 					ri.Cvar_Set ("gl_driver", "opengl32");
1271 					return VID_ERR_RETRY_QGL;
1272 				}
1273 
1274 				return VID_ERR_FAIL;
1275 			}
1276 			ri.Cvar_Get ("vid_renderer", s, CVAR_NOSET);
1277 			ri.Con_Printf (PRINT_ALL, "Getting capabilities of '%s'\n", s);
1278 		}
1279 
1280 		wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)qwglGetProcAddress("wglGetExtensionsStringARB");
1281 		wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)qwglGetProcAddress("wglGetExtensionsStringEXT");
1282 
1283 		if (!wglGetExtensionsStringARB)
1284 		{
1285 			ri.Con_Printf (PRINT_ALL, "GLimp_InitGL() - qwglGetProcAddress (wglGetExtensionsString) failed, falling back to regular PFD\n");
1286 			goto fail2;
1287 
1288 		}
1289 
1290 		if (!(init_extensions ()))
1291 		{
1292 			ri.Con_Printf (PRINT_ALL, "GLimp_InitGL() - init_extensions () failed, falling back to regular PFD\n");
1293 			goto fail2;
1294 		}
1295 
1296 		// make no rendering context current
1297 		qwglMakeCurrent(NULL, NULL);
1298 
1299 		// Destroy the rendering context...
1300 		qwglDeleteContext(hGLRC);
1301 		hGLRC = NULL;
1302 
1303 		// Get the number of pixel format available
1304 		iAttributes[0] = WGL_NUMBER_PIXEL_FORMATS_ARB;
1305 
1306 		if (wglGetPixelFormatAttribivARB(hDC, 0, 0, 1, iAttributes, iResults) == GL_FALSE)
1307 		{
1308 			ri.Con_Printf (PRINT_ALL, "GLimp_InitGL() - wglGetPixelFormatAttribivARB failed, falling back to regular PFD\n");
1309 			goto fail2;
1310 		}
1311 
1312 		//nPFD = iResults[0];
1313 
1314 		// Choose a Pixel Format Descriptor (PFD) with multisampling support.
1315 		iAttributes[0] = WGL_DOUBLE_BUFFER_ARB;
1316 		iAttributes[1] = TRUE;
1317 
1318 		iAttributes[2] = WGL_COLOR_BITS_ARB;
1319 		iAttributes[3] = (int)gl_colorbits->value;
1320 
1321 		iAttributes[4] = WGL_DEPTH_BITS_ARB;
1322 		iAttributes[5] = (int)gl_depthbits->value;
1323 
1324 		iAttributes[6] = WGL_ALPHA_BITS_ARB;
1325 		iAttributes[7] = (int)gl_alphabits->value;
1326 
1327 		iAttributes[8] = WGL_STENCIL_BITS_ARB;
1328 		iAttributes[9] = (int)gl_stencilbits->value;
1329 
1330 		iAttributes[10] = _is_multisample ? WGL_SAMPLE_BUFFERS_ARB : 0;
1331 		iAttributes[11] = _is_multisample ? TRUE : 0;
1332 
1333 		iAttributes[12] = _is_multisample ? WGL_SAMPLES_ARB : 0;
1334 		iAttributes[13] = _is_multisample ? (int)gl_ext_samples->value : 0;
1335 
1336 		iAttributes[14] = 0;
1337 		iAttributes[15] = 0;
1338 
1339 		// First attempt...
1340 		status = wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
1341 		// Failure happens not only when the function fails, but also when no matching pixel format has been found
1342 		if (status == FALSE || numFormats == 0)
1343 		{
1344 			ri.Con_Printf (PRINT_ALL, "GLimp_InitGL() - wglChoosePixelFormatARB failed, falling back to regular PFD\n");
1345 			goto fail2;
1346 		}
1347 		else
1348 		{
1349 			// Fill the list of attributes we are interested in
1350 			iAttributes[0 ] = WGL_PIXEL_TYPE_ARB;
1351 			iAttributes[1 ] = WGL_COLOR_BITS_ARB;
1352 			iAttributes[2 ] = WGL_RED_BITS_ARB;
1353 			iAttributes[3 ] = WGL_GREEN_BITS_ARB;
1354 			iAttributes[4 ] = WGL_BLUE_BITS_ARB;
1355 			iAttributes[5 ] = WGL_ALPHA_BITS_ARB;
1356 			iAttributes[6 ] = WGL_DEPTH_BITS_ARB;
1357 			iAttributes[7 ] = WGL_STENCIL_BITS_ARB;
1358 
1359 			// Since WGL_ARB_multisample and WGL_pbuffer are extensions, we must check if
1360 			// those extensions are supported before passing the corresponding enums
1361 			// to the driver. This could cause an error if they are not supported.
1362 			iAttributes[8 ] = _is_multisample ? WGL_SAMPLE_BUFFERS_ARB : WGL_PIXEL_TYPE_ARB;
1363 			iAttributes[9 ] = _is_multisample ? WGL_SAMPLES_ARB : WGL_PIXEL_TYPE_ARB;
1364 			iAttributes[12] = WGL_PIXEL_TYPE_ARB;
1365 			iAttributes[10] = WGL_DRAW_TO_WINDOW_ARB;
1366 			iAttributes[11] = WGL_DRAW_TO_BITMAP_ARB;
1367 			iAttributes[13] = WGL_DOUBLE_BUFFER_ARB;
1368 			iAttributes[14] = WGL_STEREO_ARB;
1369 			iAttributes[15] = WGL_ACCELERATION_ARB;
1370 			iAttributes[16] = WGL_NEED_PALETTE_ARB;
1371 			iAttributes[17] = WGL_NEED_SYSTEM_PALETTE_ARB;
1372 			iAttributes[18] = WGL_SWAP_LAYER_BUFFERS_ARB;
1373 			iAttributes[19] = WGL_SWAP_METHOD_ARB;
1374 			iAttributes[20] = WGL_NUMBER_OVERLAYS_ARB;
1375 			iAttributes[21] = WGL_NUMBER_UNDERLAYS_ARB;
1376 			iAttributes[22] = WGL_TRANSPARENT_ARB;
1377 			iAttributes[23] = WGL_SUPPORT_GDI_ARB;
1378 			iAttributes[24] = WGL_SUPPORT_OPENGL_ARB;
1379 
1380 			if (wglGetPixelFormatAttribivARB(hDC, pixelFormat, 0, 25, iAttributes, iResults) == GL_FALSE)
1381 			{
1382 				ri.Con_Printf (PRINT_ALL, "�����������̨������� wglGetPixelFormatAttribivARB failed\n");
1383 				goto fail2;
1384 			}
1385 
1386 			ri.Con_Printf ( PRINT_ALL ,"R1GL PFD: %d matching formats, chose %d\n  color(%d-bits (red:%d, green:%d, blue:%d)), z(%d-bits), alpha(%d-bits), stencil(%d-bits)\n",
1387 				numFormats, pixelFormat, iResults[1], iResults[2], iResults[3], iResults[4], iResults[6], iResults[5], iResults[7]);
1388 
1389 			if (_is_multisample)
1390 			{
1391 				qglEnable(GL_MULTISAMPLE_ARB);
1392 				if (gl_config.r1gl_GL_EXT_nv_multisample_filter_hint)
1393 				{
1394 					if (!strcmp (gl_ext_nv_multisample_filter_hint->string, "nicest"))
1395 						qglHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
1396 					else
1397 						qglHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_FASTEST);
1398 				}
1399 
1400 				if (iResults[8])
1401 					ri.Con_Printf ( PRINT_ALL ,"  using multisampling (FSAA), %d samples per pixel\n", iResults[9]);
1402 				else
1403 					ri.Con_Printf ( PRINT_ALL ,"  multisampling (FSAA) setup FAILED.\n");
1404 			}
1405 
1406 			if (iResults[15] != WGL_FULL_ACCELERATION_ARB)
1407 			{
1408 				ri.Con_Printf ( PRINT_ALL, "********** WARNING **********\npixelformat %d is NOT hardware accelerated!\n*****************************\n", pixelFormat);
1409 			}
1410 
1411 			ReleaseDC (temphwnd, hDC);
1412 			DestroyWindow (temphwnd);
1413 			temphwnd = NULL;
1414 
1415 			ri.Con_Printf (PRINT_DEVELOPER, "unregistering opengl window class: ");
1416 			UnregisterClass (OPENGL_CLASS, glw_state.hInstance);
1417 			ri.Con_Printf (PRINT_DEVELOPER, "ok\n");
1418 
1419 			//glw_state.hDC = GetDC (glw_state.hWnd);
1420 			if ( ( glw_state.hDC = GetDC( glw_state.hWnd ) ) == NULL )
1421 			{
1422 				ri.Con_Printf( PRINT_ALL, "�����������̨������� GetDC failed\n" );
1423 				return false;
1424 			}
1425 
1426 			SetPixelFormat (glw_state.hDC, pixelFormat, &temppfd);
1427 
1428 			/*
1429 			** startup the OpenGL subsystem by creating a context and making
1430 			** it current
1431 			*/
1432 			if ( ( glw_state.hGLRC = qwglCreateContext( glw_state.hDC ) ) == 0 )
1433 			{
1434 				ri.Con_Printf (PRINT_ALL, "�����������̨������� qwglCreateContext failed (%d)\n", GetLastError());
1435 				goto fail;
1436 			}
1437 
1438 			if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) )
1439 			{
1440 				ri.Con_Printf (PRINT_ALL, "�����������̨������� qwglMakeCurrent failed\n");
1441 				goto fail;
1442 			}
1443 
1444 			gl_config.bitDepth = iResults[1];
1445 			gl_config.wglPFD = true;
1446 		}
1447 	/*} else {
1448 
1449 		if ( !VerifyDriver() )
1450 		{
1451 			ri.Con_Printf( PRINT_ALL, "�����������̨������� no hardware acceleration detected\n" );
1452 			goto fail;
1453 		}
1454 
1455 		ri.Con_Printf( PRINT_ALL, "GL PFD: pf(%d) color(%d-bits) Z(%d-bit)\n", pixelformat, ( int ) pfd.cColorBits, ( int ) pfd.cDepthBits );
1456 		gl_config.bitDepth = pfd.cColorBits;*/
1457 	}
1458 
1459 	return VID_ERR_NONE;
1460 
1461 fail2:
1462 	// make no rendering context current
1463 	qwglMakeCurrent (NULL, NULL);
1464 
1465 	// Destroy the rendering context...
1466 	if (hGLRC)
1467 	{
1468 		qwglDeleteContext( hGLRC);
1469 		hGLRC = NULL;
1470 	}
1471 
1472 	ReleaseDC (temphwnd, hDC);
1473 	DestroyWindow (temphwnd);
1474 
1475 	ri.Con_Printf (PRINT_DEVELOPER, "unregistering opengl window class: ");
1476 	UnregisterClass (OPENGL_CLASS, glw_state.hInstance);
1477 	ri.Con_Printf (PRINT_DEVELOPER, "ok\n");
1478 	return VID_ERR_FAIL;
1479 
1480 fail:
1481 	if ( glw_state.hGLRC )
1482 	{
1483 		qwglDeleteContext( glw_state.hGLRC );
1484 		glw_state.hGLRC = NULL;
1485 	}
1486 
1487 	if ( glw_state.hDC )
1488 	{
1489 		ReleaseDC( glw_state.hWnd, glw_state.hDC );
1490 		glw_state.hDC = NULL;
1491 	}
1492 	return VID_ERR_FAIL;
1493 }
1494 
1495 /*
1496 ** GLimp_BeginFrame
1497 */
1498 #ifdef STEREO_SUPPORT
GLimp_BeginFrame(float camera_separation)1499 void GLimp_BeginFrame( float camera_separation )
1500 #else
1501 void GLimp_BeginFrame( void )
1502 #endif
1503 {
1504 #if 0
1505 	if ( gl_bitdepth->modified )
1506 	{
1507 		if ( FLOAT_NE_ZERO(gl_bitdepth->value) && !glw_state.allowdisplaydepthchange )
1508 		{
1509 			ri.Cvar_SetValue( "gl_bitdepth", 0 );
1510 			ri.Con_Printf( PRINT_ALL, "gl_bitdepth requires Win95 OSR2.x or WinNT 4.x\n" );
1511 		}
1512 		gl_bitdepth->modified = false;
1513 	}
1514 #endif
1515 
1516 #ifdef STEREO_SUPPORT
1517 	if ( camera_separation < 0 && gl_state.stereo_enabled )
1518 	{
1519 		qglDrawBuffer( GL_BACK_LEFT );
1520 	}
1521 	else if (FLOAT_GT_ZERO (camera_separation) && gl_state.stereo_enabled )
1522 	{
1523 		qglDrawBuffer( GL_BACK_RIGHT );
1524 	}
1525 	else
1526 #endif
1527 	{
1528 		qglDrawBuffer( GL_BACK );
1529 	}
1530 }
1531 
1532 /*
1533 ** GLimp_EndFrame
1534 **
1535 ** Responsible for doing a swapbuffers and possibly for other stuff
1536 ** as yet to be determined.  Probably better not to make this a GLimp
1537 ** function and instead do a call to GLimp_SwapBuffers.
1538 */
1539 
1540 void Draw_AddText (void);
GLimp_EndFrame(void)1541 void EXPORT GLimp_EndFrame (void)
1542 {
1543 	static int iDrawBuffer = 0;
1544 
1545 	if (defer_drawing)
1546 		Draw_AddText();
1547 
1548 	if (gl_drawbuffer->modified)
1549 	{
1550 		gl_drawbuffer->modified = false;
1551 		iDrawBuffer = stricmp( gl_drawbuffer->string, "GL_BACK" );
1552 	}
1553 
1554 	if (gl_defertext->modified)
1555 	{
1556 		gl_defertext->modified = false;
1557 		defer_drawing = (int)gl_defertext->value;
1558 	}
1559 
1560 	if (iDrawBuffer == 0)
1561 	{
1562 		if (gl_config.wglPFD)
1563 		{
1564 			if ( !qwglSwapBuffers( glw_state.hDC ) )
1565 			{
1566 				int err = GetLastError();
1567 				if (!IsIconic (glw_state.hWnd))
1568 					ri.Sys_Error( ERR_FATAL, "GLimp_EndFrame() - SwapBuffers() failed: %d\n", err);
1569 			}
1570 		}
1571 		else
1572 		{
1573 			if ( !SwapBuffers( glw_state.hDC ) )
1574 			{
1575 				int err = GetLastError();
1576 				if (!IsIconic (glw_state.hWnd))
1577 					ri.Sys_Error( ERR_FATAL, "GLimp_EndFrame() - SwapBuffers() failed: %d\n", err);
1578 			}
1579 		}
1580 	}
1581 }
1582 
RestoreDesktopSettings(void)1583 void RestoreDesktopSettings (void)
1584 {
1585 	if (ChangeDisplaySettings( &originalDesktopMode, 0 ) != DISP_CHANGE_SUCCESSFUL )
1586 	{
1587 		ri.Sys_Error (ERR_FATAL, "Couldn't restore desktop display settings");
1588 	}
1589 }
1590 
RestoreQ2Settings(void)1591 void RestoreQ2Settings (void)
1592 {
1593 	if (ChangeDisplaySettings( &fullScreenMode, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL )
1594 	{
1595 		ri.Sys_Error (ERR_FATAL, "Couldn't restore Quake 2 display settings");
1596 	}
1597 }
1598 
1599 /*
1600 ** GLimp_AppActivate
1601 */
1602 int R_SetMode (void);
GLimp_AppActivate(qboolean active)1603 void EXPORT GLimp_AppActivate( qboolean active )
1604 {
1605 	if ( active )
1606 	{
1607 		if (IsIconic (glw_state.hWnd))
1608 			return;
1609 
1610 		if ( FLOAT_NE_ZERO(vid_fullscreen->value))
1611 		{
1612 			if (usingDesktopSettings)
1613 			{
1614 				RestoreQ2Settings ();
1615 				usingDesktopSettings = false;
1616 			}
1617 			else
1618 			{
1619 				static qboolean warned = false;
1620 				if (!warned)
1621 				{
1622 					ri.Con_Printf (PRINT_ALL, "\2NOTE: Set vid_flip_on_switch 1 if you would like R1GL to restore your desktop resolution when switching to another application.\n");
1623 					warned = true;
1624 				}
1625 			}
1626 		}
1627 
1628 		SetForegroundWindow( glw_state.hWnd );
1629 		ShowWindow( glw_state.hWnd, SW_RESTORE );
1630 	}
1631 	else
1632 	{
1633 		if ( FLOAT_NE_ZERO(vid_fullscreen->value))
1634 		{
1635 			ShowWindow( glw_state.hWnd, SW_MINIMIZE );
1636 			if (FLOAT_NE_ZERO (vid_restore_on_switch->value) && !usingDesktopSettings)
1637 			{
1638 				RestoreDesktopSettings();
1639 				usingDesktopSettings = true;
1640 			}
1641 		}
1642 	}
1643 }
1644