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