|
|
1.1 root 1: // Main windowed and fullscreen graphics interface module. This module
2: // is used for both the software and OpenGL rendering versions of the
3: // Quake refresh engine.
4: #include <assert.h>
5: #include <float.h>
6:
7: #include "..\client\client.h"
8: #include "winquake.h"
9: //#include "zmouse.h"
10:
11: // Structure containing functions exported from refresh DLL
12: refexport_t re;
13:
14: cvar_t *win_noalttab;
15:
16: #ifndef WM_MOUSEWHEEL
17: #define WM_MOUSEWHEEL (WM_MOUSELAST+1) // message that will be supported by the OS
18: #endif
19:
20: static UINT MSH_MOUSEWHEEL;
21:
22: // Console variables that we need to access from this module
23: cvar_t *vid_gamma;
24: cvar_t *vid_ref; // Name of Refresh DLL loaded
25: cvar_t *vid_xpos; // X coordinate of window position
26: cvar_t *vid_ypos; // Y coordinate of window position
27: cvar_t *vid_fullscreen;
28:
29: // Global variables used internally by this module
30: viddef_t viddef; // global video state; used by other modules
31: HINSTANCE reflib_library; // Handle to refresh DLL
32: qboolean reflib_active = 0;
33:
34: HWND cl_hwnd; // Main window handle for life of program
35:
36: #define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) )
37:
38: LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
39:
40: static qboolean s_alttab_disabled;
41:
42: extern unsigned sys_msg_time;
43:
44: /*
45: ** WIN32 helper functions
46: */
47: extern qboolean s_win95;
48:
49: static void WIN_DisableAltTab( void )
50: {
51: if ( s_alttab_disabled )
52: return;
53:
54: if ( s_win95 )
55: {
56: BOOL old;
57:
58: SystemParametersInfo( SPI_SCREENSAVERRUNNING, 1, &old, 0 );
59: }
60: else
61: {
62: RegisterHotKey( 0, 0, MOD_ALT, VK_TAB );
63: RegisterHotKey( 0, 1, MOD_ALT, VK_RETURN );
64: }
65: s_alttab_disabled = true;
66: }
67:
68: static void WIN_EnableAltTab( void )
69: {
70: if ( s_alttab_disabled )
71: {
72: if ( s_win95 )
73: {
74: BOOL old;
75:
76: SystemParametersInfo( SPI_SCREENSAVERRUNNING, 0, &old, 0 );
77: }
78: else
79: {
80: UnregisterHotKey( 0, 0 );
81: UnregisterHotKey( 0, 1 );
82: }
83:
84: s_alttab_disabled = false;
85: }
86: }
87:
88: /*
89: ==========================================================================
90:
91: DLL GLUE
92:
93: ==========================================================================
94: */
95:
96: #define MAXPRINTMSG 4096
97: void VID_Printf (int print_level, char *fmt, ...)
98: {
99: va_list argptr;
100: char msg[MAXPRINTMSG];
101: static qboolean inupdate;
102:
103: va_start (argptr,fmt);
104: vsprintf (msg,fmt,argptr);
105: va_end (argptr);
106:
107: if (print_level == PRINT_ALL)
108: {
109: Com_Printf ("%s", msg);
110: }
111: else if ( print_level == PRINT_DEVELOPER )
112: {
113: Com_DPrintf ("%s", msg);
114: }
115: else if ( print_level == PRINT_ALERT )
116: {
117: MessageBox( 0, msg, "PRINT_ALERT", MB_ICONWARNING );
118: OutputDebugString( msg );
119: }
120: }
121:
122: void VID_Error (int err_level, char *fmt, ...)
123: {
124: va_list argptr;
125: char msg[MAXPRINTMSG];
126: static qboolean inupdate;
127:
128: va_start (argptr,fmt);
129: vsprintf (msg,fmt,argptr);
130: va_end (argptr);
131:
132: Com_Error (err_level,"%s", msg);
133: }
134:
135: //==========================================================================
136:
137: byte scantokey[128] =
138: {
139: // 0 1 2 3 4 5 6 7
140: // 8 9 A B C D E F
141: 0 , 27, '1', '2', '3', '4', '5', '6',
142: '7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0
143: 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
144: 'o', 'p', '[', ']', 13 , K_CTRL,'a', 's', // 1
145: 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
146: '\'' , '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2
147: 'b', 'n', 'm', ',', '.', '/', K_SHIFT,'*',
148: K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3
149: K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0 , K_HOME,
150: K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4
151: K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11,
152: K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5
153: 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
154: 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6
155: 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
156: 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7
157: };
158:
159: /*
160: =======
161: MapKey
162:
163: Map from windows to quake keynums
164: =======
165: */
166: int MapKey (int key)
167: {
168: int result;
169: int modified = ( key >> 16 ) & 255;
170: qboolean is_extended = false;
171:
172: if ( modified > 127)
173: return 0;
174:
175: if ( key & ( 1 << 24 ) )
176: is_extended = true;
177:
178: result = scantokey[modified];
179:
180: if ( !is_extended )
181: {
182: switch ( result )
183: {
184: case K_HOME:
185: return K_KP_HOME;
186: case K_UPARROW:
187: return K_KP_UPARROW;
188: case K_PGUP:
189: return K_KP_PGUP;
190: case K_LEFTARROW:
191: return K_KP_LEFTARROW;
192: case K_RIGHTARROW:
193: return K_KP_RIGHTARROW;
194: case K_END:
195: return K_KP_END;
196: case K_DOWNARROW:
197: return K_KP_DOWNARROW;
198: case K_PGDN:
199: return K_KP_PGDN;
200: case K_INS:
201: return K_KP_INS;
202: case K_DEL:
203: return K_KP_DEL;
204: default:
205: return result;
206: }
207: }
208: else
209: {
210: switch ( result )
211: {
212: case 0x0D:
213: return K_KP_ENTER;
214: case 0x2F:
215: return K_KP_SLASH;
216: case 0xAF:
217: return K_KP_PLUS;
218: }
219: return result;
220: }
221: }
222:
223: void AppActivate(BOOL fActive, BOOL minimize)
224: {
225: Minimized = minimize;
226:
227: Key_ClearStates();
228:
229: // we don't want to act like we're active if we're minimized
230: if (fActive && !Minimized)
231: ActiveApp = true;
232: else
233: ActiveApp = false;
234:
235: // minimize/restore mouse-capture on demand
236: if (!ActiveApp)
237: {
238: IN_Activate (false);
239: CDAudio_Activate (false);
240: S_Activate (false);
241:
242: if ( win_noalttab->value )
243: {
244: WIN_EnableAltTab();
245: }
246: }
247: else
248: {
249: IN_Activate (true);
250: CDAudio_Activate (true);
251: S_Activate (true);
252: if ( win_noalttab->value )
253: {
254: WIN_DisableAltTab();
255: }
256: }
257: }
258:
259: /*
260: ====================
261: MainWndProc
262:
263: main window procedure
264: ====================
265: */
266: LONG WINAPI MainWndProc (
267: HWND hWnd,
268: UINT uMsg,
269: WPARAM wParam,
270: LPARAM lParam)
271: {
272: LONG lRet = 0;
273:
274: if ( uMsg == MSH_MOUSEWHEEL )
275: {
276: if ( ( ( int ) wParam ) > 0 )
277: {
278: Key_Event( K_MWHEELUP, true, sys_msg_time );
279: Key_Event( K_MWHEELUP, false, sys_msg_time );
280: }
281: else
282: {
283: Key_Event( K_MWHEELDOWN, true, sys_msg_time );
284: Key_Event( K_MWHEELDOWN, false, sys_msg_time );
285: }
286: return DefWindowProc (hWnd, uMsg, wParam, lParam);
287: }
288:
289: switch (uMsg)
290: {
291: case WM_MOUSEWHEEL:
292: /*
293: ** this chunk of code theoretically only works under NT4 and Win98
294: ** since this message doesn't exist under Win95
295: */
296: if ( ( short ) HIWORD( wParam ) > 0 )
297: {
298: Key_Event( K_MWHEELUP, true, sys_msg_time );
299: Key_Event( K_MWHEELUP, false, sys_msg_time );
300: }
301: else
302: {
303: Key_Event( K_MWHEELDOWN, true, sys_msg_time );
304: Key_Event( K_MWHEELDOWN, false, sys_msg_time );
305: }
306: break;
307:
308: case WM_HOTKEY:
309: return 0;
310:
311: case WM_CREATE:
312: cl_hwnd = hWnd;
313:
314: MSH_MOUSEWHEEL = RegisterWindowMessage("MSWHEEL_ROLLMSG");
315: return DefWindowProc (hWnd, uMsg, wParam, lParam);
316:
317: case WM_PAINT:
318: SCR_DirtyScreen (); // force entire screen to update next frame
319: return DefWindowProc (hWnd, uMsg, wParam, lParam);
320:
321: case WM_DESTROY:
322: // let sound and input know about this?
323: cl_hwnd = NULL;
324: return DefWindowProc (hWnd, uMsg, wParam, lParam);
325:
326: case WM_ACTIVATE:
327: {
328: int fActive, fMinimized;
329:
330: // KJB: Watch this for problems in fullscreen modes with Alt-tabbing.
331: fActive = LOWORD(wParam);
332: fMinimized = (BOOL) HIWORD(wParam);
333:
334: AppActivate( fActive != WA_INACTIVE, fMinimized);
335:
336: if ( reflib_active )
337: re.AppActivate( !( fActive == WA_INACTIVE ) );
338: }
339: return DefWindowProc (hWnd, uMsg, wParam, lParam);
340:
341: case WM_MOVE:
342: {
343: int xPos, yPos;
344: RECT r;
345: int style;
346:
347: if (!vid_fullscreen->value)
348: {
349: xPos = (short) LOWORD(lParam); // horizontal position
350: yPos = (short) HIWORD(lParam); // vertical position
351:
352: r.left = 0;
353: r.top = 0;
354: r.right = 1;
355: r.bottom = 1;
356:
357: style = GetWindowLong( hWnd, GWL_STYLE );
358: AdjustWindowRect( &r, style, FALSE );
359:
360: Cvar_SetValue( "vid_xpos", xPos + r.left);
361: Cvar_SetValue( "vid_ypos", yPos + r.top);
362: vid_xpos->modified = false;
363: vid_ypos->modified = false;
364: if (ActiveApp)
365: IN_Activate (true);
366: }
367: }
368: return DefWindowProc (hWnd, uMsg, wParam, lParam);
369:
370: // this is complicated because Win32 seems to pack multiple mouse events into
371: // one update sometimes, so we always check all states and look for events
372: case WM_LBUTTONDOWN:
373: case WM_LBUTTONUP:
374: case WM_RBUTTONDOWN:
375: case WM_RBUTTONUP:
376: case WM_MBUTTONDOWN:
377: case WM_MBUTTONUP:
378: case WM_MOUSEMOVE:
379: {
380: int temp;
381:
382: temp = 0;
383:
384: if (wParam & MK_LBUTTON)
385: temp |= 1;
386:
387: if (wParam & MK_RBUTTON)
388: temp |= 2;
389:
390: if (wParam & MK_MBUTTON)
391: temp |= 4;
392:
393: IN_MouseEvent (temp);
394: }
395: break;
396:
397: case WM_SYSCOMMAND:
398: if ( wParam == SC_SCREENSAVE )
399: return 0;
400: return DefWindowProc (hWnd, uMsg, wParam, lParam);
401: case WM_SYSKEYDOWN:
402: if ( wParam == 13 )
403: {
404: if ( vid_fullscreen )
405: {
406: Cvar_SetValue( "vid_fullscreen", !vid_fullscreen->value );
407: }
408: return 0;
409: }
410: // fall through
411: case WM_KEYDOWN:
412: Key_Event( MapKey( lParam ), true, sys_msg_time);
413: break;
414:
415: case WM_SYSKEYUP:
416: case WM_KEYUP:
417: Key_Event( MapKey( lParam ), false, sys_msg_time);
418: break;
419:
420: case MM_MCINOTIFY:
421: {
422: LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
423: lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
424: }
425: break;
426:
427: default: // pass all unhandled messages to DefWindowProc
428: return DefWindowProc (hWnd, uMsg, wParam, lParam);
429: }
430:
431: /* return 0 if handled message, 1 if not */
432: return DefWindowProc( hWnd, uMsg, wParam, lParam );
433: }
434:
435: /*
436: ============
437: VID_Restart_f
438:
439: Console command to re-start the video mode and refresh DLL. We do this
440: simply by setting the modified flag for the vid_ref variable, which will
441: cause the entire video mode and refresh DLL to be reset on the next frame.
442: ============
443: */
444: void VID_Restart_f (void)
445: {
446: vid_ref->modified = true;
447: }
448:
449: void VID_Front_f( void )
450: {
451: SetWindowLong( cl_hwnd, GWL_EXSTYLE, WS_EX_TOPMOST );
452: SetForegroundWindow( cl_hwnd );
453: }
454:
455: /*
456: ** VID_GetModeInfo
457: */
458: typedef struct vidmode_s
459: {
460: const char *description;
461: int width, height;
462: int mode;
463: } vidmode_t;
464:
465: vidmode_t vid_modes[] =
466: {
467: { "Mode 0: 320x240", 320, 240, 0 },
468: { "Mode 1: 400x300", 400, 300, 1 },
469: { "Mode 2: 512x384", 512, 384, 2 },
470: { "Mode 3: 640x480", 640, 480, 3 },
471: { "Mode 4: 800x600", 800, 600, 4 },
472: { "Mode 5: 960x720", 960, 720, 5 },
473: { "Mode 6: 1024x768", 1024, 768, 6 },
474: { "Mode 7: 1152x864", 1152, 864, 7 },
475: { "Mode 8: 1280x960", 1280, 960, 8 },
476: { "Mode 9: 1600x1200", 1600, 1200, 9 }
477: };
478:
479: qboolean VID_GetModeInfo( int *width, int *height, int mode )
480: {
481: if ( mode < 0 || mode >= VID_NUM_MODES )
482: return false;
483:
484: *width = vid_modes[mode].width;
485: *height = vid_modes[mode].height;
486:
487: return true;
488: }
489:
490: /*
491: ** VID_UpdateWindowPosAndSize
492: */
493: void VID_UpdateWindowPosAndSize( int x, int y )
494: {
495: RECT r;
496: int style;
497: int w, h;
498:
499: r.left = 0;
500: r.top = 0;
501: r.right = viddef.width;
502: r.bottom = viddef.height;
503:
504: style = GetWindowLong( cl_hwnd, GWL_STYLE );
505: AdjustWindowRect( &r, style, FALSE );
506:
507: w = r.right - r.left;
508: h = r.bottom - r.top;
509:
510: MoveWindow( cl_hwnd, vid_xpos->value, vid_ypos->value, w, h, TRUE );
511: }
512:
513: /*
514: ** VID_NewWindow
515: */
516: void VID_NewWindow ( int width, int height)
517: {
518: viddef.width = width;
519: viddef.height = height;
520:
521: cl.force_refdef = true; // can't use a paused refdef
522: }
523:
524: void VID_FreeReflib (void)
525: {
526: if ( !FreeLibrary( reflib_library ) )
527: Com_Error( ERR_FATAL, "Reflib FreeLibrary failed" );
528: memset (&re, 0, sizeof(re));
529: reflib_library = NULL;
530: reflib_active = false;
531: }
532:
533: /*
534: ==============
535: VID_LoadRefresh
536: ==============
537: */
538: qboolean VID_LoadRefresh( char *name )
539: {
540: refimport_t ri;
541: GetRefAPI_t GetRefAPI;
542:
543: if ( reflib_active )
544: {
545: re.Shutdown();
546: VID_FreeReflib ();
547: }
548:
549: Com_Printf( "------- Loading %s -------\n", name );
550:
551: if ( ( reflib_library = LoadLibrary( name ) ) == 0 )
552: {
553: Com_Printf( "LoadLibrary(\"%s\") failed\n", name );
554:
555: return false;
556: }
557:
558: ri.Cmd_AddCommand = Cmd_AddCommand;
559: ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
560: ri.Cmd_Argc = Cmd_Argc;
561: ri.Cmd_Argv = Cmd_Argv;
562: ri.Cmd_ExecuteText = Cbuf_ExecuteText;
563: ri.Con_Printf = VID_Printf;
564: ri.Sys_Error = VID_Error;
565: ri.FS_LoadFile = FS_LoadFile;
566: ri.FS_FreeFile = FS_FreeFile;
567: ri.FS_Gamedir = FS_Gamedir;
568: ri.Cvar_Get = Cvar_Get;
569: ri.Cvar_Set = Cvar_Set;
570: ri.Cvar_SetValue = Cvar_SetValue;
571: ri.Vid_GetModeInfo = VID_GetModeInfo;
572: ri.Vid_MenuInit = VID_MenuInit;
573: ri.Vid_NewWindow = VID_NewWindow;
574:
575: if ( ( GetRefAPI = (void *) GetProcAddress( reflib_library, "GetRefAPI" ) ) == 0 )
576: Com_Error( ERR_FATAL, "GetProcAddress failed on %s", name );
577:
578: re = GetRefAPI( ri );
579:
580: if (re.api_version != API_VERSION)
581: {
582: VID_FreeReflib ();
583: Com_Error (ERR_FATAL, "%s has incompatible api_version", name);
584: }
585:
586: if ( re.Init( global_hInstance, MainWndProc ) == -1 )
587: {
588: re.Shutdown();
589: VID_FreeReflib ();
590: return false;
591: }
592:
593: Com_Printf( "------------------------------------\n");
594: reflib_active = true;
1.1.1.2 ! root 595:
! 596: //======
! 597: //PGM
! 598: vidref_val = VIDREF_OTHER;
! 599: if(vid_ref)
! 600: {
! 601: if(!strcmp (vid_ref->string, "gl"))
! 602: vidref_val = VIDREF_GL;
! 603: else if(!strcmp(vid_ref->string, "soft"))
! 604: vidref_val = VIDREF_SOFT;
! 605: }
! 606: //PGM
! 607: //======
! 608:
1.1 root 609: return true;
610: }
611:
612: /*
613: ============
614: VID_CheckChanges
615:
616: This function gets called once just before drawing each frame, and it's sole purpose in life
617: is to check to see if any of the video mode parameters have changed, and if they have to
618: update the rendering DLL and/or video mode to match.
619: ============
620: */
621: void VID_CheckChanges (void)
622: {
623: char name[100];
624:
625: if ( win_noalttab->modified )
626: {
627: if ( win_noalttab->value )
628: {
629: WIN_DisableAltTab();
630: }
631: else
632: {
633: WIN_EnableAltTab();
634: }
635: win_noalttab->modified = false;
636: }
637:
638: if ( vid_ref->modified )
639: {
640: cl.force_refdef = true; // can't use a paused refdef
641: S_StopAllSounds();
642: }
643: while (vid_ref->modified)
644: {
645: /*
646: ** refresh has changed
647: */
648: vid_ref->modified = false;
649: vid_fullscreen->modified = true;
650: cl.refresh_prepped = false;
651: cls.disable_screen = true;
652:
653: Com_sprintf( name, sizeof(name), "ref_%s.dll", vid_ref->string );
654: if ( !VID_LoadRefresh( name ) )
655: {
656: if ( strcmp (vid_ref->string, "soft") == 0 )
657: Com_Error (ERR_FATAL, "Couldn't fall back to software refresh!");
658: Cvar_Set( "vid_ref", "soft" );
659:
660: /*
661: ** drop the console if we fail to load a refresh
662: */
663: if ( cls.key_dest != key_console )
664: {
665: Con_ToggleConsole_f();
666: }
667: }
668: cls.disable_screen = false;
669: }
670:
671: /*
672: ** update our window position
673: */
674: if ( vid_xpos->modified || vid_ypos->modified )
675: {
676: if (!vid_fullscreen->value)
677: VID_UpdateWindowPosAndSize( vid_xpos->value, vid_ypos->value );
678:
679: vid_xpos->modified = false;
680: vid_ypos->modified = false;
681: }
682: }
683:
684: /*
685: ============
686: VID_Init
687: ============
688: */
689: void VID_Init (void)
690: {
691: /* Create the video variables so we know how to start the graphics drivers */
692: vid_ref = Cvar_Get ("vid_ref", "soft", CVAR_ARCHIVE);
693: vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
694: vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
695: vid_fullscreen = Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE);
696: vid_gamma = Cvar_Get( "vid_gamma", "1", CVAR_ARCHIVE );
697: win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
698:
699: /* Add some console commands that we want to handle */
700: Cmd_AddCommand ("vid_restart", VID_Restart_f);
701: Cmd_AddCommand ("vid_front", VID_Front_f);
702:
703: /*
704: ** this is a gross hack but necessary to clamp the mode for 3Dfx
705: */
706: #if 0
707: {
708: cvar_t *gl_driver = Cvar_Get( "gl_driver", "opengl32", 0 );
709: cvar_t *gl_mode = Cvar_Get( "gl_mode", "3", 0 );
710:
711: if ( stricmp( gl_driver->string, "3dfxgl" ) == 0 )
712: {
713: Cvar_SetValue( "gl_mode", 3 );
714: viddef.width = 640;
715: viddef.height = 480;
716: }
717: }
718: #endif
719:
720: /* Disable the 3Dfx splash screen */
721: putenv("FX_GLIDE_NO_SPLASH=0");
722:
723: /* Start the graphics mode and load refresh DLL */
724: VID_CheckChanges();
725: }
726:
727: /*
728: ============
729: VID_Shutdown
730: ============
731: */
732: void VID_Shutdown (void)
733: {
734: if ( reflib_active )
735: {
736: re.Shutdown ();
737: VID_FreeReflib ();
738: }
739: }
740:
741:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.