you can now build a darkplaces-dedicated executable as well as a darkplaces-glx execu...
[divverent/darkplaces.git] / vid_wgl.c
1 /*
2 Copyright (C) 1996-1997 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 // gl_vidnt.c -- NT GL vid component
21
22 #include "quakedef.h"
23 #include "winquake.h"
24 #include "resource.h"
25 #include <commctrl.h>
26
27 int cl_available = true;
28
29 int (WINAPI *qwglChoosePixelFormat)(HDC, CONST PIXELFORMATDESCRIPTOR *);
30 int (WINAPI *qwglDescribePixelFormat)(HDC, int, UINT, LPPIXELFORMATDESCRIPTOR);
31 //int (WINAPI *qwglGetPixelFormat)(HDC);
32 BOOL (WINAPI *qwglSetPixelFormat)(HDC, int, CONST PIXELFORMATDESCRIPTOR *);
33 BOOL (WINAPI *qwglSwapBuffers)(HDC);
34 HGLRC (WINAPI *qwglCreateContext)(HDC);
35 BOOL (WINAPI *qwglDeleteContext)(HGLRC);
36 PROC (WINAPI *qwglGetProcAddress)(LPCSTR);
37 BOOL (WINAPI *qwglMakeCurrent)(HDC, HGLRC);
38 BOOL (WINAPI *qwglSwapIntervalEXT)(int interval);
39 const char *(WINAPI *wglGetExtensionsStringARB)(HDC hdc);
40
41 static gl_extensionfunctionlist_t getextensionsstringfuncs[] =
42 {
43         {"wglGetExtensionsString", (void **) &qwglGetExtensionsString},
44         {NULL, NULL}
45 };
46
47 static gl_extensionfunctionlist_t wglfuncs[] =
48 {
49         {"wglChoosePixelFormat", (void **) &qwglChoosePixelFormat},
50         {"wglDescribePixelFormat", (void **) &qwglDescribePixelFormat},
51 //      {"wglGetPixelFormat", (void **) &qwglGetPixelFormat},
52         {"wglSetPixelFormat", (void **) &qwglSetPixelFormat},
53         {"wglSwapBuffers", (void **) &qwglSwapBuffers},
54         {"wglCreateContext", (void **) &qwglCreateContext},
55         {"wglDeleteContext", (void **) &qwglDeleteContext},
56         {"wglGetProcAddress", (void **) &qwglGetProcAddress},
57         {"wglMakeCurrent", (void **) &qwglMakeCurrent},
58         {NULL, NULL}
59 };
60
61 static gl_extensionfunctionlist_t wglswapintervalfuncs[] =
62 {
63         {"wglSwapIntervalEXT", (void **) &qwglSwapIntervalEXT},
64         {NULL, NULL}
65 };
66
67 #define MAX_MODE_LIST   30
68 #define VID_ROW_SIZE    3
69 #define MAXWIDTH                10000
70 #define MAXHEIGHT               10000
71
72 #define MODE_WINDOWED                   0
73 #define NO_MODE                                 (MODE_WINDOWED - 1)
74 #define MODE_FULLSCREEN_DEFAULT (MODE_WINDOWED + 1)
75
76 typedef struct {
77         modestate_t     type;
78         int                     width;
79         int                     height;
80         int                     modenum;
81         int                     dib;
82         int                     fullscreen;
83         int                     bpp;
84         char            modedesc[17];
85 } vmode_t;
86
87 typedef struct {
88         int                     width;
89         int                     height;
90 } lmode_t;
91
92 lmode_t lowresmodes[] = {
93         {320, 200},
94         {320, 240},
95         {400, 300},
96         {512, 384},
97 };
98
99 qboolean scr_skipupdate;
100
101 static vmode_t modelist[MAX_MODE_LIST];
102 static int nummodes;
103 static vmode_t badmode;
104
105 static DEVMODE gdevmode;
106 static qboolean vid_initialized = false;
107 static qboolean windowed, leavecurrentmode;
108 static qboolean vid_canalttab = false;
109 static qboolean vid_wassuspended = false;
110 static int vid_usingmouse;
111 extern qboolean mouseactive;  // from in_win.c
112 static HICON hIcon;
113
114 int DIBWidth, DIBHeight;
115 RECT WindowRect;
116 DWORD WindowStyle, ExWindowStyle;
117
118 HWND mainwindow;
119
120 int vid_modenum = NO_MODE;
121 int vid_realmode;
122 int vid_default = MODE_WINDOWED;
123 static int windowed_default;
124 unsigned char vid_curpal[256*3];
125
126 HGLRC baseRC;
127 HDC maindc;
128
129 HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow);
130
131 // global video state
132 viddef_t vid;
133
134 modestate_t modestate = MS_UNINIT;
135
136 void VID_MenuDraw (void);
137 void VID_MenuKey (int key);
138
139 LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
140 void AppActivate(BOOL fActive, BOOL minimize);
141 char *VID_GetModeDescription (int mode);
142 void ClearAllStates (void);
143 void VID_UpdateWindowStatus (void);
144
145 //====================================
146
147 int window_center_x, window_center_y, window_x, window_y, window_width, window_height;
148 RECT window_rect;
149
150 // direct draw software compatability stuff
151
152 void CenterWindow(HWND hWndCenter, int width, int height, BOOL lefttopjustify)
153 {
154         int CenterX, CenterY;
155
156         CenterX = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
157         CenterY = (GetSystemMetrics(SM_CYSCREEN) - height) / 2;
158         if (CenterX > CenterY*2)
159                 CenterX >>= 1;  // dual screens
160         CenterX = (CenterX < 0) ? 0: CenterX;
161         CenterY = (CenterY < 0) ? 0: CenterY;
162         SetWindowPos (hWndCenter, NULL, CenterX, CenterY, 0, 0,
163                         SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME);
164 }
165
166 qboolean VID_SetWindowedMode (int modenum)
167 {
168         int lastmodestate, width, height;
169         RECT rect;
170
171         lastmodestate = modestate;
172
173         WindowRect.top = WindowRect.left = 0;
174
175         WindowRect.right = modelist[modenum].width;
176         WindowRect.bottom = modelist[modenum].height;
177
178         DIBWidth = modelist[modenum].width;
179         DIBHeight = modelist[modenum].height;
180
181         WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
182         ExWindowStyle = 0;
183
184         rect = WindowRect;
185         AdjustWindowRectEx(&rect, WindowStyle, false, 0);
186
187         width = rect.right - rect.left;
188         height = rect.bottom - rect.top;
189
190         // Create the DIB window
191         mainwindow = CreateWindowEx (ExWindowStyle, gamename, gamename, WindowStyle, rect.left, rect.top, width, height, NULL, NULL, global_hInstance, NULL);
192
193         if (!mainwindow)
194                 Sys_Error ("Couldn't create DIB window");
195
196         // Center and show the DIB window
197         CenterWindow(mainwindow, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top, false);
198
199         ShowWindow (mainwindow, SW_SHOWDEFAULT);
200         UpdateWindow (mainwindow);
201
202         modestate = MS_WINDOWED;
203
204         SendMessage (mainwindow, WM_SETICON, (WPARAM)true, (LPARAM)hIcon);
205         SendMessage (mainwindow, WM_SETICON, (WPARAM)false, (LPARAM)hIcon);
206
207         return true;
208 }
209
210
211 qboolean VID_SetFullDIBMode (int modenum)
212 {
213         int lastmodestate, width, height;
214         RECT rect;
215
216         if (!leavecurrentmode)
217         {
218                 gdevmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
219                 gdevmode.dmBitsPerPel = modelist[modenum].bpp;
220                 gdevmode.dmPelsWidth = modelist[modenum].width;
221                 gdevmode.dmPelsHeight = modelist[modenum].height;
222                 gdevmode.dmSize = sizeof (gdevmode);
223
224                 if (ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
225                         Sys_Error ("Couldn't set fullscreen DIB mode");
226         }
227
228         lastmodestate = modestate;
229         modestate = MS_FULLDIB;
230
231         WindowRect.top = WindowRect.left = 0;
232
233         WindowRect.right = modelist[modenum].width;
234         WindowRect.bottom = modelist[modenum].height;
235
236         DIBWidth = modelist[modenum].width;
237         DIBHeight = modelist[modenum].height;
238
239         WindowStyle = WS_POPUP;
240         ExWindowStyle = 0;
241
242         rect = WindowRect;
243         AdjustWindowRectEx(&rect, WindowStyle, false, 0);
244
245         width = rect.right - rect.left;
246         height = rect.bottom - rect.top;
247
248         // Create the DIB window
249         mainwindow = CreateWindowEx (ExWindowStyle, gamename, gamename, WindowStyle, rect.left, rect.top, width, height, NULL, NULL, global_hInstance, NULL);
250
251         if (!mainwindow)
252                 Sys_Error ("Couldn't create DIB window");
253
254         ShowWindow (mainwindow, SW_SHOWDEFAULT);
255         UpdateWindow (mainwindow);
256
257 // needed because we're not getting WM_MOVE messages fullscreen on NT
258         window_x = 0;
259         window_y = 0;
260
261         SendMessage (mainwindow, WM_SETICON, (WPARAM)true, (LPARAM)hIcon);
262         SendMessage (mainwindow, WM_SETICON, (WPARAM)false, (LPARAM)hIcon);
263
264         return true;
265 }
266
267
268 int VID_SetMode (int modenum)
269 {
270         int original_mode;
271         qboolean stat = 0;
272         MSG msg;
273
274         if ((windowed && (modenum != 0)) || (!windowed && (modenum < 1)) || (!windowed && (modenum >= nummodes)))
275                 Sys_Error ("Bad video mode\n");
276
277         CDAudio_Pause ();
278
279         if (vid_modenum == NO_MODE)
280                 original_mode = windowed_default;
281         else
282                 original_mode = vid_modenum;
283
284         // Set either the fullscreen or windowed mode
285         if (modelist[modenum].type == MS_WINDOWED)
286                 stat = VID_SetWindowedMode(modenum);
287         else if (modelist[modenum].type == MS_FULLDIB)
288                 stat = VID_SetFullDIBMode(modenum);
289         else
290                 Sys_Error ("VID_SetMode: Bad mode type in modelist");
291
292         window_width = DIBWidth;
293         window_height = DIBHeight;
294         VID_UpdateWindowStatus ();
295
296         CDAudio_Resume ();
297
298         if (!stat)
299                 Sys_Error ("Couldn't set video mode");
300
301 // now we try to make sure we get the focus on the mode switch, because
302 // sometimes in some systems we don't.  We grab the foreground, then
303 // finish setting up, pump all our messages, and sleep for a little while
304 // to let messages finish bouncing around the system, then we put
305 // ourselves at the top of the z order, then grab the foreground again,
306 // Who knows if it helps, but it probably doesn't hurt
307         SetForegroundWindow (mainwindow);
308         vid_modenum = modenum;
309         Cvar_SetValue ("vid_mode", (float)vid_modenum);
310
311         while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
312         {
313                 TranslateMessage (&msg);
314                 DispatchMessage (&msg);
315         }
316
317         Sleep (100);
318
319         SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOCOPYBITS);
320
321         SetForegroundWindow (mainwindow);
322
323 // fix the leftover Alt from any Alt-Tab or the like that switched us away
324         ClearAllStates ();
325
326         if (!msg_suppress_1)
327                 Con_SafePrintf ("Video mode %s initialized.\n", VID_GetModeDescription (vid_modenum));
328
329         return true;
330 }
331
332
333 /*
334 ================
335 VID_UpdateWindowStatus
336 ================
337 */
338 void VID_UpdateWindowStatus (void)
339 {
340         window_rect.left = window_x;
341         window_rect.top = window_y;
342         window_rect.right = window_x + window_width;
343         window_rect.bottom = window_y + window_height;
344         window_center_x = (window_rect.left + window_rect.right) / 2;
345         window_center_y = (window_rect.top + window_rect.bottom) / 2;
346
347         IN_UpdateClipCursor ();
348 }
349
350
351 //====================================
352
353 /*
354 =================
355 VID_GetWindowSize
356 =================
357 */
358 void VID_GetWindowSize (int *x, int *y, int *width, int *height)
359 {
360         *x = *y = 0;
361         *width = WindowRect.right - WindowRect.left;
362         *height = WindowRect.bottom - WindowRect.top;
363 }
364
365
366 void VID_Finish (void)
367 {
368         int vid_usemouse;
369         if (r_render.integer && !scr_skipupdate)
370         {
371                 qglFinish();
372                 SwapBuffers(maindc);
373         }
374
375 // handle the mouse state when windowed if that's changed
376         vid_usemouse = false;
377         if (vid_mouse.integer && !key_consoleactive)
378                 vid_usemouse = true;
379         if (modestate == MS_FULLDIB)
380                 vid_usemouse = true;
381         if (!vid_activewindow)
382                 vid_usemouse = false;
383         if (vid_usemouse)
384         {
385                 if (!vid_usingmouse)
386                 {
387                         vid_usingmouse = true;
388                         IN_ActivateMouse ();
389                         IN_HideMouse();
390                 }
391         }
392         else
393         {
394                 if (vid_usingmouse)
395                 {
396                         vid_usingmouse = false;
397                         IN_DeactivateMouse ();
398                         IN_ShowMouse();
399                 }
400         }
401 }
402
403 void VID_SetDefaultMode (void)
404 {
405         IN_DeactivateMouse ();
406 }
407
408 void VID_RestoreSystemGamma(void);
409
410 void VID_Shutdown (void)
411 {
412         HGLRC hRC;
413         HDC hDC;
414         int i;
415         GLuint temp[8192];
416
417         if (vid_initialized)
418         {
419                 vid_canalttab = false;
420                 hRC = qwglGetCurrentContext();
421                 hDC = qwglGetCurrentDC();
422
423                 qwglMakeCurrent(NULL, NULL);
424
425                 // LordHavoc: free textures before closing (may help NVIDIA)
426                 for (i = 0;i < 8192;i++)
427                         temp[i] = i+1;
428                 qglDeleteTextures(8192, temp);
429
430                 if (hRC)
431                         qwglDeleteContext(hRC);
432
433                 // close the library before we get rid of the window
434                 GL_CloseLibrary();
435
436                 if (hDC && mainwindow)
437                         ReleaseDC(mainwindow, hDC);
438
439                 if (modestate == MS_FULLDIB)
440                         ChangeDisplaySettings (NULL, 0);
441
442                 if (maindc && mainwindow)
443                         ReleaseDC (mainwindow, maindc);
444
445                 AppActivate(false, false);
446
447                 VID_RestoreSystemGamma();
448         }
449 }
450
451
452 //==========================================================================
453
454
455 BOOL bSetupPixelFormat(HDC hDC)
456 {
457         static PIXELFORMATDESCRIPTOR pfd = {
458         sizeof(PIXELFORMATDESCRIPTOR),  // size of this pfd
459         1,                              // version number
460         PFD_DRAW_TO_WINDOW              // support window
461         |  PFD_SUPPORT_OPENGL   // support OpenGL
462         |  PFD_DOUBLEBUFFER ,   // double buffered
463         PFD_TYPE_RGBA,                  // RGBA type
464         24,                             // 24-bit color depth
465         0, 0, 0, 0, 0, 0,               // color bits ignored
466         0,                              // no alpha buffer
467         0,                              // shift bit ignored
468         0,                              // no accumulation buffer
469         0, 0, 0, 0,                     // accum bits ignored
470         32,                             // 32-bit z-buffer
471         0,                              // no stencil buffer
472         0,                              // no auxiliary buffer
473         PFD_MAIN_PLANE,                 // main layer
474         0,                              // reserved
475         0, 0, 0                         // layer masks ignored
476         };
477         int pixelformat;
478
479         if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 )
480         {
481                 MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);
482                 return false;
483         }
484
485         if (SetPixelFormat(hDC, pixelformat, &pfd) == false)
486         {
487                 MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);
488                 return false;
489         }
490
491         return true;
492 }
493
494
495
496 qbyte scantokey[128] =
497 {
498 //      0           1      2     3     4     5       6       7      8         9      A       B           C     D            E           F
499         0          ,27    ,'1'  ,'2'  ,'3'  ,'4'    ,'5'    ,'6'   ,'7'      ,'8'   ,'9'    ,'0'        ,'-'  ,'='         ,K_BACKSPACE,9     , // 0
500         'q'        ,'w'   ,'e'  ,'r'  ,'t'  ,'y'    ,'u'    ,'i'   ,'o'      ,'p'   ,'['    ,']'        ,13   ,K_CTRL      ,'a'        ,'s'   , // 1
501         'd'        ,'f'   ,'g'  ,'h'  ,'j'  ,'k'    ,'l'    ,';'   ,'\''     ,'`'   ,K_SHIFT,'\\'       ,'z'  ,'x'         ,'c'        ,'v'   , // 2
502         'b'        ,'n'   ,'m'  ,','  ,'.'  ,'/'    ,K_SHIFT,'*'   ,K_ALT    ,' '   ,0      ,K_F1       ,K_F2 ,K_F3        ,K_F4       ,K_F5  , // 3
503         K_F6       ,K_F7  ,K_F8 ,K_F9 ,K_F10,K_PAUSE,0      ,K_HOME,K_UPARROW,K_PGUP,'-'    ,K_LEFTARROW,'5'  ,K_RIGHTARROW,'+'        ,K_END , // 4
504         K_DOWNARROW,K_PGDN,K_INS,K_DEL,0    ,0      ,0      ,K_F11 ,K_F12    ,0     ,0      ,0          ,0    ,0           ,0          ,0     , // 5
505         0          ,0     ,0    ,0    ,0    ,0      ,0      ,0     ,0        ,0     ,0      ,0          ,0    ,0           ,0          ,0     , // 6
506         0          ,0     ,0    ,0    ,0    ,0      ,0      ,0     ,0        ,0     ,0      ,0          ,0    ,0           ,0          ,0       // 7
507 };
508
509
510 /*
511 =======
512 MapKey
513
514 Map from windows to quake keynums
515 =======
516 */
517 int MapKey (int key, int virtualkey)
518 {
519         key = (key>>16)&255;
520         if (key > 127)
521                 return 0;
522         if (scantokey[key] == 0)
523                 Con_DPrintf("key 0x%02x has no translation\n", key);
524         return scantokey[key];
525 }
526
527 /*
528 ===================================================================
529
530 MAIN WINDOW
531
532 ===================================================================
533 */
534
535 /*
536 ================
537 ClearAllStates
538 ================
539 */
540 void ClearAllStates (void)
541 {
542         int             i;
543
544 // send an up event for each key, to make sure the server clears them all
545         for (i=0 ; i<256 ; i++)
546         {
547                 Key_Event (i, false);
548         }
549
550         Key_ClearStates ();
551         IN_ClearStates ();
552 }
553
554 void VID_RestoreGameGamma(void);
555 extern qboolean host_loopactive;
556
557 void AppActivate(BOOL fActive, BOOL minimize)
558 /****************************************************************************
559 *
560 * Function:     AppActivate
561 * Parameters:   fActive - True if app is activating
562 *
563 * Description:  If the application is activating, then swap the system
564 *               into SYSPAL_NOSTATIC mode so that our palettes will display
565 *               correctly.
566 *
567 ****************************************************************************/
568 {
569         static BOOL     sound_active;
570
571         vid_activewindow = fActive;
572         vid_hidden = minimize;
573
574 // enable/disable sound on focus gain/loss
575         if (!vid_activewindow && sound_active)
576         {
577                 S_BlockSound ();
578                 sound_active = false;
579         }
580         else if (vid_activewindow && !sound_active)
581         {
582                 S_UnblockSound ();
583                 sound_active = true;
584         }
585
586         if (fActive)
587         {
588                 if (modestate == MS_FULLDIB)
589                 {
590                         if (vid_canalttab && vid_wassuspended)
591                         {
592                                 vid_wassuspended = false;
593                                 ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN);
594                                 ShowWindow(mainwindow, SW_SHOWNORMAL);
595                         }
596
597                         // LordHavoc: from dabb, fix for alt-tab bug in NVidia drivers
598                         MoveWindow(mainwindow,0,0,gdevmode.dmPelsWidth,gdevmode.dmPelsHeight,false);
599                 }
600                 if (host_loopactive)
601                         VID_RestoreGameGamma();
602         }
603
604         if (!fActive)
605         {
606                 vid_usingmouse = false;
607                 IN_DeactivateMouse ();
608                 IN_ShowMouse ();
609                 if (modestate == MS_FULLDIB && vid_canalttab)
610                 {
611                         ChangeDisplaySettings (NULL, 0);
612                         vid_wassuspended = true;
613                 }
614                 VID_RestoreSystemGamma();
615         }
616 }
617
618 LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
619
620 /* main window procedure */
621 LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM  wParam, LPARAM lParam)
622 {
623         LONG    lRet = 1;
624         int             fActive, fMinimized, temp;
625         extern unsigned int uiWheelMessage;
626
627         if ( uMsg == uiWheelMessage )
628                 uMsg = WM_MOUSEWHEEL;
629
630         switch (uMsg)
631         {
632                 case WM_KILLFOCUS:
633                         if (modestate == MS_FULLDIB)
634                                 ShowWindow(mainwindow, SW_SHOWMINNOACTIVE);
635                         break;
636
637                 case WM_CREATE:
638                         break;
639
640                 case WM_MOVE:
641                         window_x = (int) LOWORD(lParam);
642                         window_y = (int) HIWORD(lParam);
643                         VID_UpdateWindowStatus ();
644                         break;
645
646                 case WM_KEYDOWN:
647                 case WM_SYSKEYDOWN:
648                         Key_Event (MapKey(lParam, wParam), true);
649                         break;
650
651                 case WM_KEYUP:
652                 case WM_SYSKEYUP:
653                         Key_Event (MapKey(lParam, wParam), false);
654                         break;
655
656                 case WM_SYSCHAR:
657                 // keep Alt-Space from happening
658                         break;
659
660         // this is complicated because Win32 seems to pack multiple mouse events into
661         // one update sometimes, so we always check all states and look for events
662                 case WM_LBUTTONDOWN:
663                 case WM_LBUTTONUP:
664                 case WM_RBUTTONDOWN:
665                 case WM_RBUTTONUP:
666                 case WM_MBUTTONDOWN:
667                 case WM_MBUTTONUP:
668                 case WM_MOUSEMOVE:
669                         temp = 0;
670
671                         if (wParam & MK_LBUTTON)
672                                 temp |= 1;
673
674                         if (wParam & MK_RBUTTON)
675                                 temp |= 2;
676
677                         if (wParam & MK_MBUTTON)
678                                 temp |= 4;
679
680                         IN_MouseEvent (temp);
681
682                         break;
683
684                 // JACK: This is the mouse wheel with the Intellimouse
685                 // Its delta is either positive or neg, and we generate the proper
686                 // Event.
687                 case WM_MOUSEWHEEL:
688                         if ((short) HIWORD(wParam) > 0) {
689                                 Key_Event(K_MWHEELUP, true);
690                                 Key_Event(K_MWHEELUP, false);
691                         } else {
692                                 Key_Event(K_MWHEELDOWN, true);
693                                 Key_Event(K_MWHEELDOWN, false);
694                         }
695                         break;
696
697                 case WM_SIZE:
698                         break;
699
700                 case WM_CLOSE:
701                         if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit", MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES)
702                                 Sys_Quit ();
703
704                         break;
705
706                 case WM_ACTIVATE:
707                         fActive = LOWORD(wParam);
708                         fMinimized = (BOOL) HIWORD(wParam);
709                         AppActivate(!(fActive == WA_INACTIVE), fMinimized);
710
711                 // fix the leftover Alt from any Alt-Tab or the like that switched us away
712                         ClearAllStates ();
713
714                         break;
715
716                 case WM_DESTROY:
717                 {
718                         if (mainwindow)
719                                 DestroyWindow (mainwindow);
720
721                         PostQuitMessage (0);
722                 }
723                 break;
724
725                 case MM_MCINOTIFY:
726                         lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
727                         break;
728
729                 default:
730                         /* pass all unhandled messages to DefWindowProc */
731                         lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
732                 break;
733         }
734
735         /* return 1 if handled message, 0 if not */
736         return lRet;
737 }
738
739
740 /*
741 =================
742 VID_NumModes
743 =================
744 */
745 int VID_NumModes (void)
746 {
747         return nummodes;
748 }
749
750
751 /*
752 =================
753 VID_GetModePtr
754 =================
755 */
756 vmode_t *VID_GetModePtr (int modenum)
757 {
758
759         if ((modenum >= 0) && (modenum < nummodes))
760                 return &modelist[modenum];
761         else
762                 return &badmode;
763 }
764
765
766 /*
767 =================
768 VID_GetModeDescription
769 =================
770 */
771 char *VID_GetModeDescription (int mode)
772 {
773         char            *pinfo;
774         vmode_t         *pv;
775         static char     temp[100];
776
777         if ((mode < 0) || (mode >= nummodes))
778                 return NULL;
779
780         if (!leavecurrentmode)
781         {
782                 pv = VID_GetModePtr (mode);
783                 pinfo = pv->modedesc;
784         }
785         else
786         {
787                 sprintf (temp, "Desktop resolution (%dx%d)", modelist[MODE_FULLSCREEN_DEFAULT].width, modelist[MODE_FULLSCREEN_DEFAULT].height);
788                 pinfo = temp;
789         }
790
791         return pinfo;
792 }
793
794
795 // KJB: Added this to return the mode driver name in description for console
796
797 char *VID_GetExtModeDescription (int mode)
798 {
799         static char     pinfo[40];
800         vmode_t         *pv;
801
802         if ((mode < 0) || (mode >= nummodes))
803                 return NULL;
804
805         pv = VID_GetModePtr (mode);
806         if (modelist[mode].type == MS_FULLDIB)
807         {
808                 if (!leavecurrentmode)
809                         sprintf(pinfo,"%s fullscreen", pv->modedesc);
810                 else
811                         sprintf (pinfo, "Desktop resolution (%dx%d)", modelist[MODE_FULLSCREEN_DEFAULT].width, modelist[MODE_FULLSCREEN_DEFAULT].height);
812         }
813         else
814         {
815                 if (modestate == MS_WINDOWED)
816                         sprintf(pinfo, "%s windowed", pv->modedesc);
817                 else
818                         sprintf(pinfo, "windowed");
819         }
820
821         return pinfo;
822 }
823
824
825 /*
826 =================
827 VID_DescribeCurrentMode_f
828 =================
829 */
830 void VID_DescribeCurrentMode_f (void)
831 {
832         Con_Printf ("%s\n", VID_GetExtModeDescription (vid_modenum));
833 }
834
835
836 /*
837 =================
838 VID_NumModes_f
839 =================
840 */
841 void VID_NumModes_f (void)
842 {
843         if (nummodes == 1)
844                 Con_Printf ("%d video mode is available\n", nummodes);
845         else
846                 Con_Printf ("%d video modes are available\n", nummodes);
847 }
848
849
850 /*
851 =================
852 VID_DescribeMode_f
853 =================
854 */
855 void VID_DescribeMode_f (void)
856 {
857         int             t, modenum;
858
859         modenum = atoi (Cmd_Argv(1));
860
861         t = leavecurrentmode;
862         leavecurrentmode = 0;
863
864         Con_Printf ("%s\n", VID_GetExtModeDescription (modenum));
865
866         leavecurrentmode = t;
867 }
868
869
870 /*
871 =================
872 VID_DescribeModes_f
873 =================
874 */
875 void VID_DescribeModes_f (void)
876 {
877         int                     i, lnummodes, t;
878         char            *pinfo;
879         vmode_t         *pv;
880
881         lnummodes = VID_NumModes ();
882
883         t = leavecurrentmode;
884         leavecurrentmode = 0;
885
886         for (i=1 ; i<lnummodes ; i++)
887         {
888                 pv = VID_GetModePtr (i);
889                 pinfo = VID_GetExtModeDescription (i);
890                 Con_Printf ("%2d: %s\n", i, pinfo);
891         }
892
893         leavecurrentmode = t;
894 }
895
896 void VID_AddMode(int type, int width, int height, int modenum, int dib, int fullscreen, int bpp)
897 {
898         int i;
899         if (nummodes >= MAX_MODE_LIST)
900                 return;
901         modelist[nummodes].type = type;
902         modelist[nummodes].width = width;
903         modelist[nummodes].height = height;
904         modelist[nummodes].modenum = modenum;
905         modelist[nummodes].dib = dib;
906         modelist[nummodes].fullscreen = fullscreen;
907         modelist[nummodes].bpp = bpp;
908         if (bpp == 0)
909                 sprintf (modelist[nummodes].modedesc, "%dx%d", width, height);
910         else
911                 sprintf (modelist[nummodes].modedesc, "%dx%dx%d", width, height, bpp);
912         for (i = 0;i < nummodes;i++)
913         {
914                 if (!memcmp(&modelist[i], &modelist[nummodes], sizeof(vmode_t)))
915                         return;
916         }
917         nummodes++;
918 }
919
920 void VID_InitDIB (HINSTANCE hInstance)
921 {
922         int w, h;
923         WNDCLASS                wc;
924
925         // Register the frame class
926         wc.style         = 0;
927         wc.lpfnWndProc   = (WNDPROC)MainWndProc;
928         wc.cbClsExtra    = 0;
929         wc.cbWndExtra    = 0;
930         wc.hInstance     = hInstance;
931         wc.hIcon         = 0;
932         wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
933         wc.hbrBackground = NULL;
934         wc.lpszMenuName  = 0;
935         wc.lpszClassName = gamename;
936
937         if (!RegisterClass (&wc) )
938                 Sys_Error ("Couldn't register window class");
939
940         if (COM_CheckParm("-width"))
941                 w = atoi(com_argv[COM_CheckParm("-width")+1]);
942         else
943                 w = 640;
944
945         if (w < 320)
946                 w = 320;
947
948         if (COM_CheckParm("-height"))
949                 h = atoi(com_argv[COM_CheckParm("-height")+1]);
950         else
951                 h = w * 240/320;
952
953         if (h < 240)
954                 h = 240;
955
956         VID_AddMode(MS_WINDOWED, w, h, 0, 1, 0, 0);
957 }
958
959
960 /*
961 =================
962 VID_InitFullDIB
963 =================
964 */
965 void VID_InitFullDIB (HINSTANCE hInstance)
966 {
967         DEVMODE devmode;
968         int             modenum;
969         int             originalnummodes;
970         int             numlowresmodes;
971         int             j;
972         int             bpp;
973         int             done;
974         BOOL    stat;
975
976 // enumerate >8 bpp modes
977         originalnummodes = nummodes;
978         modenum = 0;
979
980         do
981         {
982                 stat = EnumDisplaySettings (NULL, modenum, &devmode);
983
984                 if ((devmode.dmBitsPerPel >= 15) && (devmode.dmPelsWidth <= MAXWIDTH) && (devmode.dmPelsHeight <= MAXHEIGHT) && (nummodes < MAX_MODE_LIST))
985                 {
986                         devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
987
988                         if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL)
989                         {
990                         // if the width is more than twice the height, reduce it by half because this
991                         // is probably a dual-screen monitor
992                                 if ((!COM_CheckParm("-noadjustaspect")) && (devmode.dmPelsWidth > (devmode.dmPelsHeight << 1)))
993                                         VID_AddMode(MS_FULLDIB, devmode.dmPelsWidth >> 1, devmode.dmPelsHeight, 0, 1, 1, 1, devmode.dmBitsPerPel);
994                                 else
995                                         VID_AddMode(MS_FULLDIB, devmode.dmPelsWidth, devmode.dmPelsHeight, 0, 0, 1, 1, devmode.dmBitsPerPel);
996                         }
997                 }
998
999                 modenum++;
1000         }
1001         while (stat);
1002
1003 // see if there are any low-res modes that aren't being reported
1004         numlowresmodes = sizeof(lowresmodes) / sizeof(lowresmodes[0]);
1005         bpp = 16;
1006         done = 0;
1007
1008         do
1009         {
1010                 for (j=0 ; (j<numlowresmodes) && (nummodes < MAX_MODE_LIST) ; j++)
1011                 {
1012                         devmode.dmBitsPerPel = bpp;
1013                         devmode.dmPelsWidth = lowresmodes[j].width;
1014                         devmode.dmPelsHeight = lowresmodes[j].height;
1015                         devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1016
1017                         if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL)
1018                                 VID_AddMode(MS_FULLDIB, devmode.dmPelsWidth, devmode.dmPelsHeight, 0, 0, 1, 1, devmode.dmBitsPerPel);
1019                 }
1020                 switch (bpp)
1021                 {
1022                         case 16:
1023                                 bpp = 32;
1024                                 break;
1025
1026                         case 32:
1027                                 bpp = 24;
1028                                 break;
1029
1030                         case 24:
1031                                 done = 1;
1032                                 break;
1033                 }
1034         }
1035         while (!done);
1036
1037         if (nummodes == originalnummodes)
1038                 Con_SafePrintf ("No fullscreen DIB modes found\n");
1039 }
1040
1041 //static int grabsysgamma = true;
1042 WORD systemgammaramps[3][256], currentgammaramps[3][256];
1043
1044 int VID_SetGamma(float prescale, float gamma, float scale, float base)
1045 {
1046         int i;
1047         HDC hdc;
1048         hdc = GetDC (NULL);
1049
1050         BuildGammaTable16(prescale, gamma, scale, base, &currentgammaramps[0][0]);
1051         for (i = 0;i < 256;i++)
1052                 currentgammaramps[1][i] = currentgammaramps[2][i] = currentgammaramps[0][i];
1053
1054         i = SetDeviceGammaRamp(hdc, &currentgammaramps[0][0]);
1055
1056         ReleaseDC (NULL, hdc);
1057         return i; // return success or failure
1058 }
1059
1060 void VID_RestoreGameGamma(void)
1061 {
1062         VID_UpdateGamma(true);
1063 }
1064
1065 void VID_GetSystemGamma(void)
1066 {
1067         HDC hdc;
1068         hdc = GetDC (NULL);
1069
1070         GetDeviceGammaRamp(hdc, &systemgammaramps[0][0]);
1071
1072         ReleaseDC (NULL, hdc);
1073 }
1074
1075 void VID_RestoreSystemGamma(void)
1076 {
1077         HDC hdc;
1078         hdc = GetDC (NULL);
1079
1080         SetDeviceGammaRamp(hdc, &systemgammaramps[0][0]);
1081
1082         ReleaseDC (NULL, hdc);
1083 }
1084
1085 //========================================================
1086 // Video menu stuff
1087 //========================================================
1088
1089 extern void M_Menu_Options_f (void);
1090 extern void M_Print (float cx, float cy, char *str);
1091 extern void M_PrintWhite (float cx, float cy, char *str);
1092 extern void M_DrawCharacter (float cx, float cy, int num);
1093 extern void M_DrawPic (float cx, float cy, char *picname);
1094
1095 static int vid_wmodes;
1096
1097 typedef struct
1098 {
1099         int modenum;
1100         char *desc;
1101         int iscur;
1102 } modedesc_t;
1103
1104 #define MAX_COLUMN_SIZE         9
1105 #define MODE_AREA_HEIGHT        (MAX_COLUMN_SIZE + 2)
1106 #define MAX_MODEDESCS           (MAX_COLUMN_SIZE*3)
1107
1108 static modedesc_t modedescs[MAX_MODEDESCS];
1109
1110 /*
1111 ================
1112 VID_MenuDraw
1113 ================
1114 */
1115 void VID_MenuDraw (void)
1116 {
1117         cachepic_t *p;
1118         char *ptr;
1119         int lnummodes, i, k, column, row;
1120         vmode_t *pv;
1121
1122         p = Draw_CachePic ("gfx/vidmodes.lmp");
1123         M_DrawPic ( (320-p->width)/2, 4, "gfx/vidmodes.lmp");
1124
1125         vid_wmodes = 0;
1126         lnummodes = VID_NumModes ();
1127
1128         for (i=1 ; (i<lnummodes) && (vid_wmodes < MAX_MODEDESCS) ; i++)
1129         {
1130                 ptr = VID_GetModeDescription (i);
1131                 pv = VID_GetModePtr (i);
1132
1133                 k = vid_wmodes;
1134
1135                 modedescs[k].modenum = i;
1136                 modedescs[k].desc = ptr;
1137                 modedescs[k].iscur = 0;
1138
1139                 if (i == vid_modenum)
1140                         modedescs[k].iscur = 1;
1141
1142                 vid_wmodes++;
1143
1144         }
1145
1146         if (vid_wmodes > 0)
1147         {
1148                 M_Print (2*8, 36+0*8, "Fullscreen Modes (WIDTHxHEIGHTxBPP)");
1149
1150                 column = 8;
1151                 row = 36+2*8;
1152
1153                 for (i=0 ; i<vid_wmodes ; i++)
1154                 {
1155                         if (modedescs[i].iscur)
1156                                 M_PrintWhite (column, row, modedescs[i].desc);
1157                         else
1158                                 M_Print (column, row, modedescs[i].desc);
1159
1160                         column += 13*8;
1161
1162                         if ((i % VID_ROW_SIZE) == (VID_ROW_SIZE - 1))
1163                         {
1164                                 column = 8;
1165                                 row += 8;
1166                         }
1167                 }
1168         }
1169
1170         M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*2, "Video modes must be set from the");
1171         M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*3, "command line with -width <width>");
1172         M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*4, "and -bpp <bits-per-pixel>");
1173         M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*6, "Select windowed mode with -window");
1174 }
1175
1176
1177 /*
1178 ================
1179 VID_MenuKey
1180 ================
1181 */
1182 void VID_MenuKey (int key)
1183 {
1184         switch (key)
1185         {
1186         case K_ESCAPE:
1187                 S_LocalSound ("misc/menu1.wav");
1188                 M_Menu_Options_f ();
1189                 break;
1190
1191         default:
1192                 break;
1193         }
1194 }
1195
1196 static HINSTANCE gldll;
1197
1198 int GL_OpenLibrary(const char *name)
1199 {
1200         Con_Printf("Loading GL driver %s\n", name);
1201         GL_CloseLibrary();
1202         if (!(gldll = LoadLibrary(name)))
1203         {
1204                 Con_Printf("Unable to LoadLibrary %s\n", name);
1205                 return false;
1206         }
1207         strcpy(gl_driver, name);
1208         return true;
1209 }
1210
1211 void GL_CloseLibrary(void)
1212 {
1213         FreeLibrary(gldll);
1214         gldll = 0;
1215         gl_driver[0] = 0;
1216         qwglGetProcAddress = NULL;
1217         gl_extensions = "";
1218         gl_platform = "";
1219         gl_platformextensions = "";
1220 }
1221
1222 void *GL_GetProcAddress(const char *name)
1223 {
1224         void *p = NULL;
1225         if (qwglGetProcAddress != NULL)
1226                 p = (void *) qwglGetProcAddress(name);
1227         if (p == NULL)
1228                 p = (void *) GetProcAddress(gldll, name);
1229         return p;
1230 }
1231 /*
1232 ===================
1233 VID_Init
1234 ===================
1235 */
1236 void VID_Init (int fullscreen, int width, int height)
1237 {
1238         int i;
1239         int basenummodes, bpp, findbpp, done;
1240         HDC hdc;
1241         DEVMODE devmode;
1242
1243         if (!GL_OpenLibrary("opengl32.dll"))
1244                 Sys_Error("Unable to load GL driver\n");
1245
1246         memset(&devmode, 0, sizeof(devmode));
1247
1248         Cmd_AddCommand ("vid_nummodes", VID_NumModes_f);
1249         Cmd_AddCommand ("vid_describecurrentmode", VID_DescribeCurrentMode_f);
1250         Cmd_AddCommand ("vid_describemode", VID_DescribeMode_f);
1251         Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f);
1252
1253         VID_GetSystemGamma();
1254
1255         hIcon = LoadIcon (global_hInstance, MAKEINTRESOURCE (IDI_ICON2));
1256
1257         InitCommonControls();
1258
1259         VID_InitDIB (global_hInstance);
1260         basenummodes = nummodes = 1;
1261
1262         VID_InitFullDIB (global_hInstance);
1263
1264         if (!fullscreen)
1265         {
1266                 hdc = GetDC (NULL);
1267
1268                 if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
1269                         Sys_Error ("Can't run in non-RGB mode");
1270
1271                 ReleaseDC (NULL, hdc);
1272
1273                 windowed = true;
1274
1275                 vid_default = MODE_WINDOWED;
1276         }
1277         else
1278         {
1279                 if (nummodes == 1)
1280                         Sys_Error ("No RGB fullscreen modes available");
1281
1282                 windowed = false;
1283
1284                 done = 0;
1285
1286                 bestmode = -1;
1287                 bestrating = 1000000000;
1288                 for (i = 0;i < nummodes;i++)
1289                 {
1290                         rating = VID_CompareMode(fullscreen, width, height, bpp, modelist[i].fullscreen, modelist[i].width, modelist[i].height, modelist[i].bpp);
1291                         if (bestrating > rating)
1292                         {
1293                                 bestrating = rating;
1294                                 bestmode = i;
1295                         }
1296                 }
1297
1298                 if (bestmode < 0)
1299                         Sys_Error ("Specified video mode not available");
1300         }
1301
1302         vid_initialized = true;
1303
1304         VID_SetMode (vid_default);
1305
1306         maindc = GetDC(mainwindow);
1307         bSetupPixelFormat(maindc);
1308
1309         if (!gl_checkextension("wgl", wglfuncs, NULL, false))
1310                 Sys_Error("wgl functions not found\n");
1311
1312         baseRC = qwglCreateContext( maindc );
1313         if (!baseRC)
1314                 Sys_Error ("Could not initialize GL (wglCreateContext failed).\n\nMake sure you are in 65536 color mode, and try running -window.");
1315         if (!qwglMakeCurrent( maindc, baseRC ))
1316                 Sys_Error ("wglMakeCurrent failed");
1317
1318         gl_renderer = qglGetString(GL_RENDERER);
1319         gl_vendor = qglGetString(GL_VENDOR);
1320         gl_version = qglGetString(GL_VERSION);
1321         gl_extensions = qglGetString(GL_EXTENSIONS);
1322         gl_platformname = "WGL";
1323         gl_platformextensions = "";
1324
1325         if (gl_checkextension("WGL_ARB_extensions_string", extensionsstringfuncs, NULL, false))
1326                 gl_platformextensions = qwglGetExtensionsStringARB(maindc);
1327
1328         gl_videosyncavailable = gl_checkextension("WGL_EXT_swap_control", wglswapintervalfuncs, NULL, false);
1329
1330         GL_Init ();
1331
1332         // LordHavoc: special differences for ATI (broken 8bit color when also using 32bit? weird!)
1333         if (strncasecmp(gl_vendor,"ATI",3)==0)
1334         {
1335                 if (strncasecmp(gl_renderer,"Rage Pro",8)==0)
1336                         isRagePro = true;
1337         }
1338         if (strncasecmp(gl_renderer,"Matrox G200 Direct3D",20)==0) // a D3D driver for GL? sigh...
1339                 isG200 = true;
1340
1341         vid_realmode = vid_modenum;
1342
1343         vid_menudrawfn = VID_MenuDraw;
1344         vid_menukeyfn = VID_MenuKey;
1345
1346         strcpy (badmode.modedesc, "Bad mode");
1347         vid_canalttab = true;
1348
1349         vid_hidden = false;
1350 }
1351