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