]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - vid_wgl.c
Don't duplicate the entity relinking when using CSQC.
[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 // vid_wgl.c -- NT GL vid component
21
22 #ifdef _MSC_VER
23 #pragma comment(lib, "comctl32.lib")
24 #endif
25
26 #ifdef SUPPORTDIRECTX
27 // Include DX libs
28 #ifdef _MSC_VER
29 #pragma comment(lib, "dinput8.lib")
30 #pragma comment(lib, "dxguid.lib")
31 #endif
32 #ifndef DIRECTINPUT_VERSION
33 #       define DIRECTINPUT_VERSION 0x0500  /* Version 5.0 */
34 #endif
35 #endif
36
37 #include "quakedef.h"
38 #include <windows.h>
39 #include <mmsystem.h>
40 #ifdef SUPPORTDIRECTX
41 #include <dsound.h>
42 #endif
43 #include "resource.h"
44 #include <commctrl.h>
45 #ifdef SUPPORTDIRECTX
46 #include <dinput.h>
47 #endif
48 #include "dpsoftrast.h"
49
50 #ifdef SUPPORTD3D
51 #include <d3d9.h>
52
53 cvar_t vid_dx9 = {CVAR_SAVE, "vid_dx9", "0", "use Microsoft Direct3D9(r) for rendering"};
54 cvar_t vid_dx9_hal = {CVAR_SAVE, "vid_dx9_hal", "1", "enables hardware rendering (1), otherwise software reference rasterizer (0 - very slow), note that 0 is necessary when using NVPerfHUD (which renders in hardware but requires this option to enable it)"};
55 cvar_t vid_dx9_softvertex = {CVAR_SAVE, "vid_dx9_softvertex", "0", "enables software vertex processing (for compatibility testing?  or if you have a very fast CPU), usually you want this off"};
56 cvar_t vid_dx9_triplebuffer = {CVAR_SAVE, "vid_dx9_triplebuffer", "0", "enables triple buffering when using vid_vsync in fullscreen, this options adds some latency and only helps when framerate is below 60 so you usually don't want it"};
57 //cvar_t vid_dx10 = {CVAR_SAVE, "vid_dx10", "1", "use Microsoft Direct3D10(r) for rendering"};
58 //cvar_t vid_dx11 = {CVAR_SAVE, "vid_dx11", "1", "use Microsoft Direct3D11(r) for rendering"};
59
60 D3DPRESENT_PARAMETERS vid_d3dpresentparameters;
61
62 // we declare this in vid_shared.c because it is required by dedicated server and all clients when SUPPORTD3D is defined
63 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
64
65 LPDIRECT3D9 vid_d3d9;
66 D3DCAPS9 vid_d3d9caps;
67 qboolean vid_d3ddevicelost;
68 #endif
69
70 extern HINSTANCE global_hInstance;
71
72 static HINSTANCE gldll;
73
74 #ifndef WM_MOUSEWHEEL
75 #define WM_MOUSEWHEEL                   0x020A
76 #endif
77
78 // Tell startup code that we have a client
79 int cl_available = true;
80
81 qboolean vid_supportrefreshrate = true;
82
83 static int (WINAPI *qwglChoosePixelFormat)(HDC, CONST PIXELFORMATDESCRIPTOR *);
84 static int (WINAPI *qwglDescribePixelFormat)(HDC, int, UINT, LPPIXELFORMATDESCRIPTOR);
85 //static int (WINAPI *qwglGetPixelFormat)(HDC);
86 static BOOL (WINAPI *qwglSetPixelFormat)(HDC, int, CONST PIXELFORMATDESCRIPTOR *);
87 static BOOL (WINAPI *qwglSwapBuffers)(HDC);
88 static HGLRC (WINAPI *qwglCreateContext)(HDC);
89 static BOOL (WINAPI *qwglDeleteContext)(HGLRC);
90 static HGLRC (WINAPI *qwglGetCurrentContext)(VOID);
91 static HDC (WINAPI *qwglGetCurrentDC)(VOID);
92 static PROC (WINAPI *qwglGetProcAddress)(LPCSTR);
93 static BOOL (WINAPI *qwglMakeCurrent)(HDC, HGLRC);
94 static BOOL (WINAPI *qwglSwapIntervalEXT)(int interval);
95 static const char *(WINAPI *qwglGetExtensionsStringARB)(HDC hdc);
96 static BOOL (WINAPI *qwglChoosePixelFormatARB)(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
97 static BOOL (WINAPI *qwglGetPixelFormatAttribivARB)(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
98
99 static dllfunction_t wglfuncs[] =
100 {
101         {"wglChoosePixelFormat", (void **) &qwglChoosePixelFormat},
102         {"wglDescribePixelFormat", (void **) &qwglDescribePixelFormat},
103 //      {"wglGetPixelFormat", (void **) &qwglGetPixelFormat},
104         {"wglSetPixelFormat", (void **) &qwglSetPixelFormat},
105         {"wglSwapBuffers", (void **) &qwglSwapBuffers},
106         {"wglCreateContext", (void **) &qwglCreateContext},
107         {"wglDeleteContext", (void **) &qwglDeleteContext},
108         {"wglGetProcAddress", (void **) &qwglGetProcAddress},
109         {"wglMakeCurrent", (void **) &qwglMakeCurrent},
110         {"wglGetCurrentContext", (void **) &qwglGetCurrentContext},
111         {"wglGetCurrentDC", (void **) &qwglGetCurrentDC},
112         {NULL, NULL}
113 };
114
115 static dllfunction_t wglswapintervalfuncs[] =
116 {
117         {"wglSwapIntervalEXT", (void **) &qwglSwapIntervalEXT},
118         {NULL, NULL}
119 };
120
121 static dllfunction_t wglpixelformatfuncs[] =
122 {
123         {"wglChoosePixelFormatARB", (void **) &qwglChoosePixelFormatARB},
124         {"wglGetPixelFormatAttribivARB", (void **) &qwglGetPixelFormatAttribivARB},
125         {NULL, NULL}
126 };
127
128 static DEVMODE gdevmode, initialdevmode;
129 static vid_mode_t desktop_mode;
130 static qboolean vid_initialized = false;
131 static qboolean vid_wassuspended = false;
132 static qboolean vid_usingmouse = false;
133 static qboolean vid_usinghidecursor = false;
134 static qboolean vid_usingvsync = false;
135 static qboolean vid_usevsync = false;
136 static HICON hIcon;
137
138 // used by cd_win.c and snd_win.c
139 HWND mainwindow;
140
141 static HDC       baseDC;
142 static HGLRC baseRC;
143
144 static HDC vid_softhdc;
145 static HGDIOBJ vid_softhdc_backup;
146 static BITMAPINFO vid_softbmi;
147 static HBITMAP vid_softdibhandle;
148
149 //HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow);
150
151 static qboolean vid_isfullscreen;
152
153 //void VID_MenuDraw (void);
154 //void VID_MenuKey (int key);
155
156 LONG WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
157 void AppActivate(BOOL fActive, BOOL minimize);
158 static void ClearAllStates(void);
159 qboolean VID_InitModeGL(viddef_mode_t *mode);
160 qboolean VID_InitModeSOFT(viddef_mode_t *mode);
161
162 //====================================
163
164 static int window_x, window_y;
165
166 static qboolean mouseinitialized;
167
168 #ifdef SUPPORTDIRECTX
169 static qboolean dinput;
170 #define DINPUT_BUFFERSIZE           16
171 #define iDirectInputCreate(a,b,c,d)     pDirectInputCreate(a,b,c,d)
172
173 static HRESULT (WINAPI *pDirectInputCreate)(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUT * lplpDirectInput, LPUNKNOWN punkOuter);
174 #endif
175
176 // LordHavoc: thanks to backslash for this support for mouse buttons 4 and 5
177 /* backslash :: imouse explorer buttons */
178 /* These are #ifdefed out for non-Win2K in the February 2001 version of
179    MS's platform SDK, but we need them for compilation. . . */
180 #ifndef WM_XBUTTONDOWN
181    #define WM_XBUTTONDOWN      0x020B
182    #define WM_XBUTTONUP      0x020C
183 #endif
184 #ifndef MK_XBUTTON1
185    #define MK_XBUTTON1         0x0020
186    #define MK_XBUTTON2         0x0040
187 #endif
188 #ifndef MK_XBUTTON3
189 // LordHavoc: lets hope this allows more buttons in the future...
190    #define MK_XBUTTON3         0x0080
191    #define MK_XBUTTON4         0x0100
192    #define MK_XBUTTON5         0x0200
193    #define MK_XBUTTON6         0x0400
194    #define MK_XBUTTON7         0x0800
195 #endif
196 /* :: backslash */
197
198 // mouse variables
199 static int                      mouse_buttons;
200 static int                      mouse_oldbuttonstate;
201
202 static unsigned int uiWheelMessage;
203 #ifdef SUPPORTDIRECTX
204 static qboolean dinput_acquired;
205
206 static unsigned int             mstate_di;
207 #endif
208
209 static cvar_t vid_forcerefreshrate = {0, "vid_forcerefreshrate", "0", "try to set the given vid_refreshrate even if Windows doesn't list it as valid video mode"};
210
211 #ifdef SUPPORTDIRECTX
212 static LPDIRECTINPUT            g_pdi;
213 static LPDIRECTINPUTDEVICE      g_pMouse;
214 static HINSTANCE hInstDI;
215 #endif
216
217 // forward-referenced functions
218 static void IN_StartupMouse (void);
219 static void AdjustWindowBounds(int fullscreen, int *width, int *height, viddef_mode_t *mode, DWORD WindowStyle, RECT *rect);
220
221 //====================================
222
223 qboolean vid_reallyhidden = true;
224 #ifdef SUPPORTD3D
225 qboolean vid_begunscene = false;
226 #endif
227 void VID_Finish (void)
228 {
229 #ifdef SUPPORTD3D
230         HRESULT hr;
231 #endif
232         vid_hidden = vid_reallyhidden;
233
234         vid_usevsync = vid_vsync.integer && !cls.timedemo && qwglSwapIntervalEXT;
235
236         if (!vid_hidden)
237         {
238                 switch(vid.renderpath)
239                 {
240                 case RENDERPATH_GL11:
241                 case RENDERPATH_GL13:
242                 case RENDERPATH_GL20:
243                 case RENDERPATH_GLES1:
244                 case RENDERPATH_GLES2:
245                         if (vid_usingvsync != vid_usevsync)
246                         {
247                                 vid_usingvsync = vid_usevsync;
248                                 qwglSwapIntervalEXT (vid_usevsync);
249                         }
250                         if (r_speeds.integer == 2 || gl_finish.integer)
251                                 GL_Finish();
252                         SwapBuffers(baseDC);
253                         break;
254                 case RENDERPATH_D3D9:
255 #ifdef SUPPORTD3D
256                         if (vid_begunscene)
257                         {
258                                 IDirect3DDevice9_EndScene(vid_d3d9dev);
259                                 vid_begunscene = false;
260                         }
261                         if (!vid_reallyhidden)
262                         {
263                                 if (!vid_d3ddevicelost)
264                                 {
265                                         vid_hidden = vid_reallyhidden;
266                                         hr = IDirect3DDevice9_Present(vid_d3d9dev, NULL, NULL, NULL, NULL);
267                                         if (hr == D3DERR_DEVICELOST)
268                                         {
269                                                 vid_d3ddevicelost = true;
270                                                 vid_hidden = true;
271                                                 Sleep(100);
272                                         }
273                                 }
274                                 else
275                                 {
276                                         hr = IDirect3DDevice9_TestCooperativeLevel(vid_d3d9dev);
277                                         switch(hr)
278                                         {
279                                         case D3DERR_DEVICELOST:
280                                                 vid_d3ddevicelost = true;
281                                                 vid_hidden = true;
282                                                 Sleep(100);
283                                                 break;
284                                         case D3DERR_DEVICENOTRESET:
285                                                 vid_d3ddevicelost = false;
286                                                 vid_hidden = vid_reallyhidden;
287                                                 R_Modules_DeviceLost();
288                                                 IDirect3DDevice9_Reset(vid_d3d9dev, &vid_d3dpresentparameters);
289                                                 R_Modules_DeviceRestored();
290                                                 break;
291                                         case D3D_OK:
292                                                 vid_hidden = vid_reallyhidden;
293                                                 IDirect3DDevice9_Present(vid_d3d9dev, NULL, NULL, NULL, NULL);
294                                                 break;
295                                         }
296                                 }
297                                 if (!vid_begunscene && !vid_hidden)
298                                 {
299                                         IDirect3DDevice9_BeginScene(vid_d3d9dev);
300                                         vid_begunscene = true;
301                                 }
302                         }
303 #endif
304                         break;
305                 case RENDERPATH_D3D10:
306                         break;
307                 case RENDERPATH_D3D11:
308                         break;
309                 case RENDERPATH_SOFT:
310                         DPSOFTRAST_Finish();
311 //                      baseDC = GetDC(mainwindow);
312                         BitBlt(baseDC, 0, 0, vid.width, vid.height, vid_softhdc, 0, 0, SRCCOPY);
313 //                      ReleaseDC(mainwindow, baseDC);
314 //                      baseDC = NULL;
315                         break;
316                 }
317         }
318
319         // make sure a context switch can happen every frame - Logitech drivers
320         // input drivers sometimes eat cpu time every 3 seconds or lag badly
321         // without this help
322         Sleep(0);
323
324         VID_UpdateGamma();
325 }
326
327 //==========================================================================
328
329
330 static unsigned char scantokey[128] =
331 {
332 //  0           1        2     3     4     5       6           7      8         9      A          B           C       D            E           F
333         0          ,K_ESCAPE,'1'  ,'2'  ,'3'  ,'4'    ,'5'        ,'6'   ,'7'      ,'8'   ,'9'       ,'0'        ,'-'    ,'='         ,K_BACKSPACE,K_TAB,//0
334         'q'        ,'w'     ,'e'  ,'r'  ,'t'  ,'y'    ,'u'        ,'i'   ,'o'      ,'p'   ,'['       ,']'        ,K_ENTER,K_CTRL      ,'a'        ,'s'  ,//1
335         'd'        ,'f'     ,'g'  ,'h'  ,'j'  ,'k'    ,'l'        ,';'   ,'\''     ,'`'   ,K_SHIFT   ,'\\'       ,'z'    ,'x'         ,'c'        ,'v'  ,//2
336         'b'        ,'n'     ,'m'  ,','  ,'.'  ,'/'    ,K_SHIFT    ,'*'   ,K_ALT    ,' '   ,K_CAPSLOCK,K_F1       ,K_F2   ,K_F3        ,K_F4       ,K_F5 ,//3
337         K_F6       ,K_F7    ,K_F8 ,K_F9 ,K_F10,K_PAUSE,K_SCROLLOCK,K_HOME,K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5 ,K_RIGHTARROW,K_KP_PLUS  ,K_END,//4
338         K_DOWNARROW,K_PGDN  ,K_INS,K_DEL,0    ,0      ,0          ,K_F11 ,K_F12    ,0     ,0         ,0          ,0      ,0           ,0          ,0    ,//5
339         0          ,0       ,0    ,0    ,0    ,0      ,0          ,0     ,0        ,0     ,0         ,0          ,0      ,0           ,0          ,0    ,//6
340         0          ,0       ,0    ,0    ,0    ,0      ,0          ,0     ,0        ,0     ,0         ,0          ,0      ,0           ,0          ,0     //7
341 };
342
343
344 /*
345 =======
346 MapKey
347
348 Map from windows to quake keynums
349 =======
350 */
351 static int MapKey (int key, int virtualkey)
352 {
353         int result;
354         int modified = (key >> 16) & 255;
355         qboolean is_extended = false;
356
357         if (modified < 128 && scantokey[modified])
358                 result = scantokey[modified];
359         else
360         {
361                 result = 0;
362                 Con_DPrintf("key 0x%02x (0x%8x, 0x%8x) has no translation\n", modified, key, virtualkey);
363         }
364
365         if (key & (1 << 24))
366                 is_extended = true;
367
368         if ( !is_extended )
369         {
370                 if(((GetKeyState(VK_NUMLOCK)) & 0xffff) == 0)
371                         return result;
372
373                 switch ( result )
374                 {
375                 case K_HOME:
376                         return K_KP_HOME;
377                 case K_UPARROW:
378                         return K_KP_UPARROW;
379                 case K_PGUP:
380                         return K_KP_PGUP;
381                 case K_LEFTARROW:
382                         return K_KP_LEFTARROW;
383                 case K_RIGHTARROW:
384                         return K_KP_RIGHTARROW;
385                 case K_END:
386                         return K_KP_END;
387                 case K_DOWNARROW:
388                         return K_KP_DOWNARROW;
389                 case K_PGDN:
390                         return K_KP_PGDN;
391                 case K_INS:
392                         return K_KP_INS;
393                 case K_DEL:
394                         return K_KP_DEL;
395                 default:
396                         return result;
397                 }
398         }
399         else
400         {
401                 if(virtualkey == VK_NUMLOCK)
402                         return K_NUMLOCK;
403
404                 switch ( result )
405                 {
406                 case 0x0D:
407                         return K_KP_ENTER;
408                 case 0x2F:
409                         return K_KP_SLASH;
410                 case 0xAF:
411                         return K_KP_PLUS;
412                 }
413                 return result;
414         }
415 }
416
417 /*
418 ===================================================================
419
420 MAIN WINDOW
421
422 ===================================================================
423 */
424
425 /*
426 ================
427 ClearAllStates
428 ================
429 */
430 static void ClearAllStates (void)
431 {
432         Key_ReleaseAll();
433         if (vid_usingmouse)
434                 mouse_oldbuttonstate = 0;
435 }
436
437 void AppActivate(BOOL fActive, BOOL minimize)
438 /****************************************************************************
439 *
440 * Function:     AppActivate
441 * Parameters:   fActive - True if app is activating
442 *
443 * Description:  If the application is activating, then swap the system
444 *               into SYSPAL_NOSTATIC mode so that our palettes will display
445 *               correctly.
446 *
447 ****************************************************************************/
448 {
449         static qboolean sound_active = false;  // initially blocked by Sys_InitConsole()
450
451         vid_activewindow = fActive != FALSE;
452         vid_reallyhidden = minimize != FALSE;
453
454         // enable/disable sound on focus gain/loss
455         if ((!vid_reallyhidden && vid_activewindow) || !snd_mutewhenidle.integer)
456         {
457                 if (!sound_active)
458                 {
459                         S_UnblockSound ();
460                         sound_active = true;
461                 }
462         }
463         else
464         {
465                 if (sound_active)
466                 {
467                         S_BlockSound ();
468                         sound_active = false;
469                 }
470         }
471
472         if (fActive)
473         {
474                 if (vid_isfullscreen)
475                 {
476                         if (vid_wassuspended)
477                         {
478                                 vid_wassuspended = false;
479                                 if (gldll)
480                                 {
481                                         ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN);
482                                         ShowWindow(mainwindow, SW_SHOWNORMAL);
483                                 }
484                         }
485
486                         // LordHavoc: from dabb, fix for alt-tab bug in NVidia drivers
487                         if (gldll)
488                                 MoveWindow(mainwindow,0,0,gdevmode.dmPelsWidth,gdevmode.dmPelsHeight,false);
489                 }
490         }
491
492         if (!fActive)
493         {
494                 VID_SetMouse(false, false, false);
495                 if (vid_isfullscreen)
496                 {
497                         if (gldll)
498                                 ChangeDisplaySettings (NULL, CDS_FULLSCREEN);
499                         vid_wassuspended = true;
500                 }
501         }
502 }
503
504 //TODO: move it around in vid_wgl.c since I dont think this is the right position
505 void Sys_SendKeyEvents (void)
506 {
507         MSG msg;
508
509         while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
510         {
511                 if (!GetMessage (&msg, NULL, 0, 0))
512                         Sys_Quit (1);
513
514                 TranslateMessage (&msg);
515                 DispatchMessage (&msg);
516         }
517 }
518
519 #ifdef CONFIG_CD
520 LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
521 #endif
522
523 static keynum_t buttonremap[16] =
524 {
525         K_MOUSE1,
526         K_MOUSE2,
527         K_MOUSE3,
528         K_MOUSE4,
529         K_MOUSE5,
530         K_MOUSE6,
531         K_MOUSE7,
532         K_MOUSE8,
533         K_MOUSE9,
534         K_MOUSE10,
535         K_MOUSE11,
536         K_MOUSE12,
537         K_MOUSE13,
538         K_MOUSE14,
539         K_MOUSE15,
540         K_MOUSE16,
541 };
542
543 /* main window procedure */
544 LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM  wParam, LPARAM lParam)
545 {
546         LONG    lRet = 1;
547         int             fActive, fMinimized, temp;
548         unsigned char state[256];
549         const unsigned int UNICODE_BUFFER_LENGTH = 4;
550         WCHAR unicode[UNICODE_BUFFER_LENGTH];
551         int             vkey;
552         int             charlength;
553         qboolean down = false;
554
555         if ( uMsg == uiWheelMessage )
556                 uMsg = WM_MOUSEWHEEL;
557
558         switch (uMsg)
559         {
560                 case WM_KILLFOCUS:
561                         if (vid_isfullscreen)
562                                 ShowWindow(mainwindow, SW_SHOWMINNOACTIVE);
563                         break;
564
565                 case WM_CREATE:
566                         break;
567
568                 case WM_MOVE:
569                         window_x = (short) LOWORD(lParam);
570                         window_y = (short) HIWORD(lParam);
571                         VID_SetMouse(false, false, false);
572                         break;
573
574                 case WM_KEYDOWN:
575                 case WM_SYSKEYDOWN:
576                         down = true;
577                 case WM_KEYUP:
578                 case WM_SYSKEYUP:
579                         vkey = MapKey(lParam, wParam);
580                         GetKeyboardState (state);
581                         // alt/ctrl/shift tend to produce funky ToAscii values,
582                         // and if it's not a single character we don't know care about it
583                         charlength = ToUnicode(wParam, lParam >> 16, state, unicode, UNICODE_BUFFER_LENGTH, 0);
584                         if(vkey == K_ALT || vkey == K_CTRL || vkey == K_SHIFT || charlength == 0)
585                                 unicode[0] = 0;
586                         else if(charlength == 2)
587                                 unicode[0] = unicode[1];
588                         if (!VID_JoyBlockEmulatedKeys(vkey))
589                                 Key_Event(vkey, unicode[0], down);
590                         break;
591
592                 case WM_SYSCHAR:
593                 // keep Alt-Space from happening
594                         break;
595
596                 case WM_SYSCOMMAND:
597                         // prevent screensaver from occuring while the active window
598                         // note: password-locked screensavers on Vista still work
599                         if (vid_activewindow && ((wParam & 0xFFF0) == SC_SCREENSAVE || (wParam & 0xFFF0) == SC_MONITORPOWER))
600                                 lRet = 0;
601                         else
602                                 lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
603                         break;
604
605         // this is complicated because Win32 seems to pack multiple mouse events into
606         // one update sometimes, so we always check all states and look for events
607                 case WM_LBUTTONDOWN:
608                 case WM_LBUTTONUP:
609                 case WM_RBUTTONDOWN:
610                 case WM_RBUTTONUP:
611                 case WM_MBUTTONDOWN:
612                 case WM_MBUTTONUP:
613                 case WM_XBUTTONDOWN:   // backslash :: imouse explorer buttons
614                 case WM_XBUTTONUP:      // backslash :: imouse explorer buttons
615                 case WM_MOUSEMOVE:
616                         temp = 0;
617
618                         if (wParam & MK_LBUTTON)
619                                 temp |= 1;
620
621                         if (wParam & MK_RBUTTON)
622                                 temp |= 2;
623
624                         if (wParam & MK_MBUTTON)
625                                 temp |= 4;
626
627                         /* backslash :: imouse explorer buttons */
628                         if (wParam & MK_XBUTTON1)
629                                 temp |= 8;
630
631                         if (wParam & MK_XBUTTON2)
632                                 temp |= 16;
633                         /* :: backslash */
634
635                         // LordHavoc: lets hope this allows more buttons in the future...
636                         if (wParam & MK_XBUTTON3)
637                                 temp |= 32;
638                         if (wParam & MK_XBUTTON4)
639                                 temp |= 64;
640                         if (wParam & MK_XBUTTON5)
641                                 temp |= 128;
642                         if (wParam & MK_XBUTTON6)
643                                 temp |= 256;
644                         if (wParam & MK_XBUTTON7)
645                                 temp |= 512;
646
647 #ifdef SUPPORTDIRECTX
648                         if (!dinput_acquired)
649 #endif
650                         {
651                                 // perform button actions
652                                 int i;
653                                 for (i=0 ; i<mouse_buttons && i < 16 ; i++)
654                                         if ((temp ^ mouse_oldbuttonstate) & (1<<i))
655                                                 Key_Event (buttonremap[i], 0, (temp & (1<<i)) != 0);
656                                 mouse_oldbuttonstate = temp;
657                         }
658
659                         break;
660
661                 // JACK: This is the mouse wheel with the Intellimouse
662                 // Its delta is either positive or neg, and we generate the proper
663                 // Event.
664                 case WM_MOUSEWHEEL:
665                         if ((short) HIWORD(wParam) > 0) {
666                                 Key_Event(K_MWHEELUP, 0, true);
667                                 Key_Event(K_MWHEELUP, 0, false);
668                         } else {
669                                 Key_Event(K_MWHEELDOWN, 0, true);
670                                 Key_Event(K_MWHEELDOWN, 0, false);
671                         }
672                         break;
673
674                 case WM_SIZE:
675                         break;
676
677                 case WM_CLOSE:
678                         if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit", MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES)
679                                 Sys_Quit (0);
680
681                         break;
682
683                 case WM_ACTIVATE:
684                         fActive = LOWORD(wParam);
685                         fMinimized = (BOOL) HIWORD(wParam);
686                         AppActivate(!(fActive == WA_INACTIVE), fMinimized);
687
688                 // fix the leftover Alt from any Alt-Tab or the like that switched us away
689                         ClearAllStates ();
690
691                         break;
692
693                 //case WM_DESTROY:
694                 //      PostQuitMessage (0);
695                 //      break;
696
697                 case MM_MCINOTIFY:
698 #ifdef CONFIG_CD
699                         lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
700 #endif
701                         break;
702
703                 default:
704                         /* pass all unhandled messages to DefWindowProc */
705                         lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
706                 break;
707         }
708
709         /* return 1 if handled message, 0 if not */
710         return lRet;
711 }
712
713 static void GL_CloseLibrary(void)
714 {
715         if (gldll)
716         {
717                 FreeLibrary(gldll);
718                 gldll = 0;
719                 gl_driver[0] = 0;
720                 qwglGetProcAddress = NULL;
721                 gl_extensions = "";
722                 gl_platform = "";
723                 gl_platformextensions = "";
724         }
725 }
726
727 static int GL_OpenLibrary(const char *name)
728 {
729         Con_Printf("Loading OpenGL driver %s\n", name);
730         GL_CloseLibrary();
731         if (!(gldll = LoadLibrary(name)))
732         {
733                 Con_Printf("Unable to LoadLibrary %s\n", name);
734                 return false;
735         }
736         strlcpy(gl_driver, name, sizeof(gl_driver));
737         return true;
738 }
739
740 void *GL_GetProcAddress(const char *name)
741 {
742         if (gldll)
743         {
744                 void *p = NULL;
745                 if (qwglGetProcAddress != NULL)
746                         p = (void *) qwglGetProcAddress(name);
747                 if (p == NULL)
748                         p = (void *) GetProcAddress(gldll, name);
749                 return p;
750         }
751         else
752                 return NULL;
753 }
754
755 #ifndef WGL_ARB_pixel_format
756 #define WGL_NUMBER_PIXEL_FORMATS_ARB   0x2000
757 #define WGL_DRAW_TO_WINDOW_ARB         0x2001
758 #define WGL_DRAW_TO_BITMAP_ARB         0x2002
759 #define WGL_ACCELERATION_ARB           0x2003
760 #define WGL_NEED_PALETTE_ARB           0x2004
761 #define WGL_NEED_SYSTEM_PALETTE_ARB    0x2005
762 #define WGL_SWAP_LAYER_BUFFERS_ARB     0x2006
763 #define WGL_SWAP_METHOD_ARB            0x2007
764 #define WGL_NUMBER_OVERLAYS_ARB        0x2008
765 #define WGL_NUMBER_UNDERLAYS_ARB       0x2009
766 #define WGL_TRANSPARENT_ARB            0x200A
767 #define WGL_TRANSPARENT_RED_VALUE_ARB  0x2037
768 #define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
769 #define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
770 #define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
771 #define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
772 #define WGL_SHARE_DEPTH_ARB            0x200C
773 #define WGL_SHARE_STENCIL_ARB          0x200D
774 #define WGL_SHARE_ACCUM_ARB            0x200E
775 #define WGL_SUPPORT_GDI_ARB            0x200F
776 #define WGL_SUPPORT_OPENGL_ARB         0x2010
777 #define WGL_DOUBLE_BUFFER_ARB          0x2011
778 #define WGL_STEREO_ARB                 0x2012
779 #define WGL_PIXEL_TYPE_ARB             0x2013
780 #define WGL_COLOR_BITS_ARB             0x2014
781 #define WGL_RED_BITS_ARB               0x2015
782 #define WGL_RED_SHIFT_ARB              0x2016
783 #define WGL_GREEN_BITS_ARB             0x2017
784 #define WGL_GREEN_SHIFT_ARB            0x2018
785 #define WGL_BLUE_BITS_ARB              0x2019
786 #define WGL_BLUE_SHIFT_ARB             0x201A
787 #define WGL_ALPHA_BITS_ARB             0x201B
788 #define WGL_ALPHA_SHIFT_ARB            0x201C
789 #define WGL_ACCUM_BITS_ARB             0x201D
790 #define WGL_ACCUM_RED_BITS_ARB         0x201E
791 #define WGL_ACCUM_GREEN_BITS_ARB       0x201F
792 #define WGL_ACCUM_BLUE_BITS_ARB        0x2020
793 #define WGL_ACCUM_ALPHA_BITS_ARB       0x2021
794 #define WGL_DEPTH_BITS_ARB             0x2022
795 #define WGL_STENCIL_BITS_ARB           0x2023
796 #define WGL_AUX_BUFFERS_ARB            0x2024
797 #define WGL_NO_ACCELERATION_ARB        0x2025
798 #define WGL_GENERIC_ACCELERATION_ARB   0x2026
799 #define WGL_FULL_ACCELERATION_ARB      0x2027
800 #define WGL_SWAP_EXCHANGE_ARB          0x2028
801 #define WGL_SWAP_COPY_ARB              0x2029
802 #define WGL_SWAP_UNDEFINED_ARB         0x202A
803 #define WGL_TYPE_RGBA_ARB              0x202B
804 #define WGL_TYPE_COLORINDEX_ARB        0x202C
805 #endif
806
807 #ifndef WGL_ARB_multisample
808 #define WGL_SAMPLE_BUFFERS_ARB         0x2041
809 #define WGL_SAMPLES_ARB                0x2042
810 #endif
811
812
813 static void IN_Init(void);
814 void VID_Init(void)
815 {
816         WNDCLASS wc;
817
818 #ifdef SUPPORTD3D
819         Cvar_RegisterVariable(&vid_dx9);
820         Cvar_RegisterVariable(&vid_dx9_hal);
821         Cvar_RegisterVariable(&vid_dx9_softvertex);
822         Cvar_RegisterVariable(&vid_dx9_triplebuffer);
823 //      Cvar_RegisterVariable(&vid_dx10);
824 //      Cvar_RegisterVariable(&vid_dx11);
825 #endif
826
827         InitCommonControls();
828         hIcon = LoadIcon (global_hInstance, MAKEINTRESOURCE (IDI_ICON1));
829
830         // Register the frame class
831         wc.style         = 0;
832         wc.lpfnWndProc   = (WNDPROC)MainWndProc;
833         wc.cbClsExtra    = 0;
834         wc.cbWndExtra    = 0;
835         wc.hInstance     = global_hInstance;
836         wc.hIcon         = hIcon;
837         wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
838         wc.hbrBackground = NULL;
839         wc.lpszMenuName  = 0;
840         wc.lpszClassName = "DarkPlacesWindowClass";
841
842         if (!RegisterClass (&wc))
843                 Con_Printf ("Couldn't register window class\n");
844
845         memset(&initialdevmode, 0, sizeof(initialdevmode));
846         EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &initialdevmode);
847
848         desktop_mode.width = initialdevmode.dmPelsWidth;
849         desktop_mode.height = initialdevmode.dmPelsHeight;
850         desktop_mode.bpp = initialdevmode.dmBitsPerPel;
851         desktop_mode.refreshrate = initialdevmode.dmDisplayFrequency;
852         desktop_mode.pixelheight_num = 1;
853         desktop_mode.pixelheight_denom = 1; // Win32 apparently does not provide this (FIXME)
854
855         IN_Init();
856 }
857
858 qboolean VID_InitModeGL(viddef_mode_t *mode)
859 {
860         int i;
861         HDC hdc;
862         RECT rect;
863         MSG msg;
864         PIXELFORMATDESCRIPTOR pfd =
865         {
866                 sizeof(PIXELFORMATDESCRIPTOR),  // size of this pfd
867                 1,                              // version number
868                 PFD_DRAW_TO_WINDOW              // support window
869                 |  PFD_SUPPORT_OPENGL   // support OpenGL
870                 |  PFD_DOUBLEBUFFER ,   // double buffered
871                 PFD_TYPE_RGBA,                  // RGBA type
872                 24,                             // 24-bit color depth
873                 0, 0, 0, 0, 0, 0,               // color bits ignored
874                 0,                              // no alpha buffer
875                 0,                              // shift bit ignored
876                 0,                              // no accumulation buffer
877                 0, 0, 0, 0,                     // accum bits ignored
878                 32,                             // 32-bit z-buffer
879                 0,                              // no stencil buffer
880                 0,                              // no auxiliary buffer
881                 PFD_MAIN_PLANE,                 // main layer
882                 0,                              // reserved
883                 0, 0, 0                         // layer masks ignored
884         };
885         int windowpass;
886         int pixelformat, newpixelformat;
887         UINT numpixelformats;
888         DWORD WindowStyle, ExWindowStyle;
889         const char *gldrivername;
890         int depth;
891         DEVMODE thismode;
892         qboolean foundmode, foundgoodmode;
893         int *a;
894         float *af;
895         int attribs[128];
896         float attribsf[16];
897         int bpp = mode->bitsperpixel;
898         int width = mode->width;
899         int height = mode->height;
900         int refreshrate = (int)floor(mode->refreshrate+0.5);
901         int stereobuffer = mode->stereobuffer;
902         int samples = mode->samples;
903         int fullscreen = mode->fullscreen;
904
905         if (vid_initialized)
906                 Sys_Error("VID_InitMode called when video is already initialised");
907
908         // if stencil is enabled, ask for alpha too
909         if (bpp >= 32)
910         {
911                 pfd.cRedBits = 8;
912                 pfd.cGreenBits = 8;
913                 pfd.cBlueBits = 8;
914                 pfd.cAlphaBits = 8;
915                 pfd.cDepthBits = 24;
916                 pfd.cStencilBits = 8;
917         }
918         else
919         {
920                 pfd.cRedBits = 5;
921                 pfd.cGreenBits = 5;
922                 pfd.cBlueBits = 5;
923                 pfd.cAlphaBits = 0;
924                 pfd.cDepthBits = 16;
925                 pfd.cStencilBits = 0;
926         }
927
928         if (stereobuffer)
929                 pfd.dwFlags |= PFD_STEREO;
930
931         a = attribs;
932         af = attribsf;
933         *a++ = WGL_DRAW_TO_WINDOW_ARB;
934         *a++ = GL_TRUE;
935         *a++ = WGL_ACCELERATION_ARB;
936         *a++ = WGL_FULL_ACCELERATION_ARB;
937         *a++ = WGL_DOUBLE_BUFFER_ARB;
938         *a++ = true;
939
940         if (bpp >= 32)
941         {
942                 *a++ = WGL_RED_BITS_ARB;
943                 *a++ = 8;
944                 *a++ = WGL_GREEN_BITS_ARB;
945                 *a++ = 8;
946                 *a++ = WGL_BLUE_BITS_ARB;
947                 *a++ = 8;
948                 *a++ = WGL_ALPHA_BITS_ARB;
949                 *a++ = 8;
950                 *a++ = WGL_DEPTH_BITS_ARB;
951                 *a++ = 24;
952                 *a++ = WGL_STENCIL_BITS_ARB;
953                 *a++ = 8;
954         }
955         else
956         {
957                 *a++ = WGL_RED_BITS_ARB;
958                 *a++ = 1;
959                 *a++ = WGL_GREEN_BITS_ARB;
960                 *a++ = 1;
961                 *a++ = WGL_BLUE_BITS_ARB;
962                 *a++ = 1;
963                 *a++ = WGL_DEPTH_BITS_ARB;
964                 *a++ = 16;
965         }
966
967         if (stereobuffer)
968         {
969                 *a++ = WGL_STEREO_ARB;
970                 *a++ = GL_TRUE;
971         }
972
973         if (samples > 1)
974         {
975                 *a++ = WGL_SAMPLE_BUFFERS_ARB;
976                 *a++ = 1;
977                 *a++ = WGL_SAMPLES_ARB;
978                 *a++ = samples;
979         }
980
981         *a = 0;
982         *af = 0;
983
984         gldrivername = "opengl32.dll";
985 // COMMANDLINEOPTION: Windows WGL: -gl_driver <drivername> selects a GL driver library, default is opengl32.dll, useful only for 3dfxogl.dll or 3dfxvgl.dll, if you don't know what this is for, you don't need it
986         i = COM_CheckParm("-gl_driver");
987         if (i && i < com_argc - 1)
988                 gldrivername = com_argv[i + 1];
989         if (!GL_OpenLibrary(gldrivername))
990         {
991                 Con_Printf("Unable to load GL driver %s\n", gldrivername);
992                 return false;
993         }
994
995         memset(&gdevmode, 0, sizeof(gdevmode));
996
997         vid_isfullscreen = false;
998         if (fullscreen)
999         {
1000                 if(vid_desktopfullscreen.integer)
1001                 {
1002                         foundmode = true;
1003                         gdevmode = initialdevmode;
1004                         width = mode->width = gdevmode.dmPelsWidth;
1005                         height = mode->height = gdevmode.dmPelsHeight;
1006                         bpp = mode->bitsperpixel = gdevmode.dmBitsPerPel;
1007                 }
1008                 else if(vid_forcerefreshrate.integer)
1009                 {
1010                         foundmode = true;
1011                         gdevmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1012                         gdevmode.dmBitsPerPel = bpp;
1013                         gdevmode.dmPelsWidth = width;
1014                         gdevmode.dmPelsHeight = height;
1015                         gdevmode.dmSize = sizeof (gdevmode);
1016                         if(refreshrate)
1017                         {
1018                                 gdevmode.dmFields |= DM_DISPLAYFREQUENCY;
1019                                 gdevmode.dmDisplayFrequency = refreshrate;
1020                         }
1021                 }
1022                 else
1023                 {
1024                         if(refreshrate == 0)
1025                                 refreshrate = initialdevmode.dmDisplayFrequency; // default vid_refreshrate to the rate of the desktop
1026
1027                         foundmode = false;
1028                         foundgoodmode = false;
1029
1030                         thismode.dmSize = sizeof(thismode);
1031                         thismode.dmDriverExtra = 0;
1032                         for(i = 0; EnumDisplaySettings(NULL, i, &thismode); ++i)
1033                         {
1034                                 if(~thismode.dmFields & (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY))
1035                                 {
1036                                         Con_DPrintf("enumerating modes yielded a bogus item... please debug this\n");
1037                                         continue;
1038                                 }
1039                                 if(developer_extra.integer)
1040                                         Con_DPrintf("Found mode %dx%dx%dbpp %dHz... ", (int)thismode.dmPelsWidth, (int)thismode.dmPelsHeight, (int)thismode.dmBitsPerPel, (int)thismode.dmDisplayFrequency);
1041                                 if(thismode.dmBitsPerPel != (DWORD)bpp)
1042                                 {
1043                                         if(developer_extra.integer)
1044                                                 Con_DPrintf("wrong bpp\n");
1045                                         continue;
1046                                 }
1047                                 if(thismode.dmPelsWidth != (DWORD)width)
1048                                 {
1049                                         if(developer_extra.integer)
1050                                                 Con_DPrintf("wrong width\n");
1051                                         continue;
1052                                 }
1053                                 if(thismode.dmPelsHeight != (DWORD)height)
1054                                 {
1055                                         if(developer_extra.integer)
1056                                                 Con_DPrintf("wrong height\n");
1057                                         continue;
1058                                 }
1059
1060                                 if(foundgoodmode)
1061                                 {
1062                                         // if we have a good mode, make sure this mode is better than the previous one, and allowed by the refreshrate
1063                                         if(thismode.dmDisplayFrequency > (DWORD)refreshrate)
1064                                         {
1065                                                 if(developer_extra.integer)
1066                                                         Con_DPrintf("too high refresh rate\n");
1067                                                 continue;
1068                                         }
1069                                         else if(thismode.dmDisplayFrequency <= gdevmode.dmDisplayFrequency)
1070                                         {
1071                                                 if(developer_extra.integer)
1072                                                         Con_DPrintf("doesn't beat previous best match (too low)\n");
1073                                                 continue;
1074                                         }
1075                                 }
1076                                 else if(foundmode)
1077                                 {
1078                                         // we do have one, but it isn't good... make sure it has a lower frequency than the previous one
1079                                         if(thismode.dmDisplayFrequency >= gdevmode.dmDisplayFrequency)
1080                                         {
1081                                                 if(developer_extra.integer)
1082                                                         Con_DPrintf("doesn't beat previous best match (too high)\n");
1083                                                 continue;
1084                                         }
1085                                 }
1086                                 // otherwise, take anything
1087
1088                                 memcpy(&gdevmode, &thismode, sizeof(gdevmode));
1089                                 if(thismode.dmDisplayFrequency <= (DWORD)refreshrate)
1090                                         foundgoodmode = true;
1091                                 else
1092                                 {
1093                                         if(developer_extra.integer)
1094                                                 Con_DPrintf("(out of range)\n");
1095                                 }
1096                                 foundmode = true;
1097                                 if(developer_extra.integer)
1098                                         Con_DPrintf("accepted\n");
1099                         }
1100                 }
1101
1102                 if (!foundmode)
1103                 {
1104                         VID_Shutdown();
1105                         Con_Printf("Unable to find the requested mode %dx%dx%dbpp\n", width, height, bpp);
1106                         return false;
1107                 }
1108                 else if(ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
1109                 {
1110                         VID_Shutdown();
1111                         Con_Printf("Unable to change to requested mode %dx%dx%dbpp\n", width, height, bpp);
1112                         return false;
1113                 }
1114
1115                 vid_isfullscreen = true;
1116                 WindowStyle = WS_POPUP;
1117                 ExWindowStyle = WS_EX_TOPMOST;
1118         }
1119         else
1120         {
1121                 hdc = GetDC (NULL);
1122                 i = GetDeviceCaps(hdc, RASTERCAPS);
1123                 depth = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
1124                 ReleaseDC (NULL, hdc);
1125                 if (i & RC_PALETTE)
1126                 {
1127                         VID_Shutdown();
1128                         Con_Print("Can't run in non-RGB mode\n");
1129                         return false;
1130                 }
1131                 if (bpp > depth)
1132                 {
1133                         VID_Shutdown();
1134                         Con_Print("A higher desktop depth is required to run this video mode\n");
1135                         return false;
1136                 }
1137
1138                 WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
1139                 ExWindowStyle = 0;
1140         }
1141
1142         AdjustWindowBounds(fullscreen, &width, &height, mode, WindowStyle, &rect);
1143
1144         pixelformat = 0;
1145         newpixelformat = 0;
1146         // start out at the final windowpass if samples is 1 as it's the only feature we need extended pixel formats for
1147         for (windowpass = samples == 1;windowpass < 2;windowpass++)
1148         {
1149                 gl_extensions = "";
1150                 gl_platformextensions = "";
1151
1152                 mainwindow = CreateWindowEx (ExWindowStyle, "DarkPlacesWindowClass", gamename, WindowStyle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, global_hInstance, NULL);
1153                 if (!mainwindow)
1154                 {
1155                         Con_Printf("CreateWindowEx(%d, %s, %s, %d, %d, %d, %d, %d, %p, %p, %p, %p) failed\n", (int)ExWindowStyle, "DarkPlacesWindowClass", gamename, (int)WindowStyle, (int)(rect.left), (int)(rect.top), (int)(rect.right - rect.left), (int)(rect.bottom - rect.top), (void *)NULL, (void *)NULL, (void *)global_hInstance, (void *)NULL);
1156                         VID_Shutdown();
1157                         return false;
1158                 }
1159
1160                 baseDC = GetDC(mainwindow);
1161
1162                 if (!newpixelformat)
1163                         newpixelformat = ChoosePixelFormat(baseDC, &pfd);
1164                 pixelformat = newpixelformat;
1165                 if (!pixelformat)
1166                 {
1167                         VID_Shutdown();
1168                         Con_Printf("ChoosePixelFormat(%p, %p) failed\n", (void *)baseDC, (void *)&pfd);
1169                         return false;
1170                 }
1171
1172                 if (SetPixelFormat(baseDC, pixelformat, &pfd) == false)
1173                 {
1174                         VID_Shutdown();
1175                         Con_Printf("SetPixelFormat(%p, %d, %p) failed\n", (void *)baseDC, pixelformat, (void *)&pfd);
1176                         return false;
1177                 }
1178
1179                 if (!GL_CheckExtension("wgl", wglfuncs, NULL, false))
1180                 {
1181                         VID_Shutdown();
1182                         Con_Print("wgl functions not found\n");
1183                         return false;
1184                 }
1185
1186                 baseRC = qwglCreateContext(baseDC);
1187                 if (!baseRC)
1188                 {
1189                         VID_Shutdown();
1190                         Con_Print("Could not initialize GL (wglCreateContext failed).\n\nMake sure you are in 65536 color mode, and try running -window.\n");
1191                         return false;
1192                 }
1193                 if (!qwglMakeCurrent(baseDC, baseRC))
1194                 {
1195                         VID_Shutdown();
1196                         Con_Printf("wglMakeCurrent(%p, %p) failed\n", (void *)baseDC, (void *)baseRC);
1197                         return false;
1198                 }
1199
1200                 if ((qglGetString = (const GLubyte* (GLAPIENTRY *)(GLenum name))GL_GetProcAddress("glGetString")) == NULL)
1201                 {
1202                         VID_Shutdown();
1203                         Con_Print("glGetString not found\n");
1204                         return false;
1205                 }
1206                 if ((qwglGetExtensionsStringARB = (const char *(WINAPI *)(HDC hdc))GL_GetProcAddress("wglGetExtensionsStringARB")) == NULL)
1207                         Con_Print("wglGetExtensionsStringARB not found\n");
1208
1209                 gl_extensions = (const char *)qglGetString(GL_EXTENSIONS);
1210                 gl_platform = "WGL";
1211                 gl_platformextensions = "";
1212
1213                 if (qwglGetExtensionsStringARB)
1214                         gl_platformextensions = (const char *)qwglGetExtensionsStringARB(baseDC);
1215
1216                 if (!gl_extensions)
1217                         gl_extensions = "";
1218                 if (!gl_platformextensions)
1219                         gl_platformextensions = "";
1220
1221                 // now some nice Windows pain:
1222                 // we have created a window, we needed one to find out if there are
1223                 // any multisample pixel formats available, the problem is that to
1224                 // actually use one of those multisample formats we now have to
1225                 // recreate the window (yes Microsoft OpenGL really is that bad)
1226
1227                 if (windowpass == 0)
1228                 {
1229                         if (!GL_CheckExtension("WGL_ARB_pixel_format", wglpixelformatfuncs, "-noarbpixelformat", false) || !qwglChoosePixelFormatARB(baseDC, attribs, attribsf, 1, &newpixelformat, &numpixelformats) || !newpixelformat)
1230                                 break;
1231                         // ok we got one - do it all over again with newpixelformat
1232                         qwglMakeCurrent(NULL, NULL);
1233                         qwglDeleteContext(baseRC);baseRC = 0;
1234                         ReleaseDC(mainwindow, baseDC);baseDC = 0;
1235                         // eat up any messages waiting for us
1236                         while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1237                         {
1238                                 TranslateMessage (&msg);
1239                                 DispatchMessage (&msg);
1240                         }
1241                 }
1242         }
1243
1244         /*
1245         if (!fullscreen)
1246                 SetWindowPos (mainwindow, NULL, CenterX, CenterY, 0, 0,SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME);
1247         */
1248
1249         ShowWindow (mainwindow, SW_SHOWDEFAULT);
1250         UpdateWindow (mainwindow);
1251
1252         // now we try to make sure we get the focus on the mode switch, because
1253         // sometimes in some systems we don't.  We grab the foreground, then
1254         // finish setting up, pump all our messages, and sleep for a little while
1255         // to let messages finish bouncing around the system, then we put
1256         // ourselves at the top of the z order, then grab the foreground again,
1257         // Who knows if it helps, but it probably doesn't hurt
1258         SetForegroundWindow (mainwindow);
1259
1260         while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1261         {
1262                 TranslateMessage (&msg);
1263                 DispatchMessage (&msg);
1264         }
1265
1266         Sleep (100);
1267
1268         SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOCOPYBITS);
1269
1270         SetForegroundWindow (mainwindow);
1271
1272         // fix the leftover Alt from any Alt-Tab or the like that switched us away
1273         ClearAllStates ();
1274
1275 // COMMANDLINEOPTION: Windows WGL: -novideosync disables WGL_EXT_swap_control
1276         GL_CheckExtension("WGL_EXT_swap_control", wglswapintervalfuncs, "-novideosync", false);
1277
1278         GL_Init ();
1279
1280         //vid_menudrawfn = VID_MenuDraw;
1281         //vid_menukeyfn = VID_MenuKey;
1282         vid_usingmouse = false;
1283         vid_usinghidecursor = false;
1284         vid_usingvsync = false;
1285         vid_reallyhidden = vid_hidden = false;
1286         vid_initialized = true;
1287
1288         IN_StartupMouse ();
1289
1290         if (qwglSwapIntervalEXT)
1291         {
1292                 vid_usevsync = vid_vsync.integer != 0;
1293                 vid_usingvsync = vid_vsync.integer != 0;
1294                 qwglSwapIntervalEXT (vid_usevsync);
1295         }
1296
1297         return true;
1298 }
1299
1300 static void AdjustWindowBounds(int fullscreen, int *width, int *height, viddef_mode_t *mode, DWORD WindowStyle, RECT *rect)
1301 {
1302         int CenterX, CenterY;
1303
1304         rect->top = 0;
1305         rect->left = 0;
1306         rect->right = *width;
1307         rect->bottom = *height;
1308         AdjustWindowRectEx(rect, WindowStyle, false, 0);
1309
1310         if (fullscreen)
1311         {
1312                 CenterX = 0;
1313                 CenterY = 0;
1314         }
1315         else
1316         {
1317                 RECT workArea;
1318                 SystemParametersInfo(SPI_GETWORKAREA, NULL, &workArea, 0);
1319                 int workWidth = workArea.right - workArea.left;
1320                 int workHeight = workArea.bottom - workArea.top;
1321
1322                 // if height/width matches physical screen height/width, adjust it to available desktop size
1323                 // and allow 2 pixels on top for the title bar so the window can be moved
1324                 const int titleBarPixels = 2;
1325                 if (*width == GetSystemMetrics(SM_CXSCREEN) && (*height == GetSystemMetrics(SM_CYSCREEN) || *height == workHeight - titleBarPixels))
1326                 {
1327                         rect->right -= *width - workWidth;
1328                         *width = mode->width = workWidth;
1329                         rect->bottom -= *height - (workHeight - titleBarPixels);
1330                         *height = mode->height = workHeight - titleBarPixels;
1331                         CenterX = 0;
1332                         CenterY = titleBarPixels;
1333                 }
1334                 else
1335                 {
1336                         CenterX = max(0, (workWidth - *width) / 2);
1337                         CenterY = max(0, (workHeight - *height) / 2);
1338                 }
1339         }
1340
1341         // x and y may be changed by WM_MOVE messages
1342         window_x = CenterX;
1343         window_y = CenterY;
1344         rect->left += CenterX;
1345         rect->right += CenterX;
1346         rect->top += CenterY;
1347         rect->bottom += CenterY;
1348 }
1349
1350 #ifdef SUPPORTD3D
1351 static D3DADAPTER_IDENTIFIER9 d3d9adapteridentifier;
1352
1353 extern cvar_t gl_info_extensions;
1354 extern cvar_t gl_info_vendor;
1355 extern cvar_t gl_info_renderer;
1356 extern cvar_t gl_info_version;
1357 extern cvar_t gl_info_platform;
1358 extern cvar_t gl_info_driver;
1359 qboolean VID_InitModeDX(viddef_mode_t *mode, int version)
1360 {
1361         int deviceindex;
1362         RECT rect;
1363         MSG msg;
1364         DWORD WindowStyle, ExWindowStyle;
1365         int bpp = mode->bitsperpixel;
1366         int width = mode->width;
1367         int height = mode->height;
1368         int refreshrate = (int)floor(mode->refreshrate+0.5);
1369 //      int stereobuffer = mode->stereobuffer;
1370         int samples = mode->samples;
1371         int fullscreen = mode->fullscreen;
1372         int numdevices;
1373
1374         if (vid_initialized)
1375                 Sys_Error("VID_InitMode called when video is already initialised");
1376
1377         vid_isfullscreen = fullscreen != 0;
1378         if (fullscreen)
1379         {
1380                 WindowStyle = WS_POPUP;
1381                 ExWindowStyle = WS_EX_TOPMOST;
1382         }
1383         else
1384         {
1385                 WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
1386                 ExWindowStyle = 0;
1387         }
1388
1389         AdjustWindowBounds(fullscreen, &width, &height, mode, WindowStyle, &rect);
1390
1391         gl_extensions = "";
1392         gl_platformextensions = "";
1393
1394         mainwindow = CreateWindowEx (ExWindowStyle, "DarkPlacesWindowClass", gamename, WindowStyle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, global_hInstance, NULL);
1395         if (!mainwindow)
1396         {
1397                 Con_Printf("CreateWindowEx(%d, %s, %s, %d, %d, %d, %d, %d, %p, %p, %p, %p) failed\n", (int)ExWindowStyle, "DarkPlacesWindowClass", gamename, (int)WindowStyle, (int)(rect.left), (int)(rect.top), (int)(rect.right - rect.left), (int)(rect.bottom - rect.top), (void *)NULL, (void *)NULL, global_hInstance, (void *)NULL);
1398                 VID_Shutdown();
1399                 return false;
1400         }
1401
1402         baseDC = GetDC(mainwindow);
1403
1404         vid_d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
1405         if (!vid_d3d9)
1406                 Sys_Error("VID_InitMode: Direct3DCreate9 failed");
1407
1408         numdevices = IDirect3D9_GetAdapterCount(vid_d3d9);
1409         vid_d3d9dev = NULL;
1410         memset(&d3d9adapteridentifier, 0, sizeof(d3d9adapteridentifier));
1411         for (deviceindex = 0;deviceindex < numdevices && !vid_d3d9dev;deviceindex++)
1412         {
1413                 memset(&vid_d3dpresentparameters, 0, sizeof(vid_d3dpresentparameters));
1414 //              vid_d3dpresentparameters.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
1415                 vid_d3dpresentparameters.Flags = 0;
1416                 vid_d3dpresentparameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
1417                 vid_d3dpresentparameters.hDeviceWindow = mainwindow;
1418                 vid_d3dpresentparameters.BackBufferWidth = width;
1419                 vid_d3dpresentparameters.BackBufferHeight = height;
1420                 vid_d3dpresentparameters.MultiSampleType = samples > 1 ? (D3DMULTISAMPLE_TYPE)samples : D3DMULTISAMPLE_NONE;
1421                 vid_d3dpresentparameters.BackBufferCount = fullscreen ? (vid_dx9_triplebuffer.integer ? 3 : 2) : 1;
1422                 vid_d3dpresentparameters.FullScreen_RefreshRateInHz = fullscreen ? refreshrate : 0;
1423                 vid_d3dpresentparameters.Windowed = !fullscreen;
1424                 vid_d3dpresentparameters.EnableAutoDepthStencil = true;
1425                 vid_d3dpresentparameters.AutoDepthStencilFormat = bpp > 16 ? D3DFMT_D24S8 : D3DFMT_D16;
1426                 vid_d3dpresentparameters.BackBufferFormat = fullscreen?D3DFMT_X8R8G8B8:D3DFMT_UNKNOWN;
1427                 vid_d3dpresentparameters.PresentationInterval = vid_vsync.integer ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
1428
1429                 memset(&d3d9adapteridentifier, 0, sizeof(d3d9adapteridentifier));
1430                 IDirect3D9_GetAdapterIdentifier(vid_d3d9, deviceindex, 0, &d3d9adapteridentifier);
1431
1432                 IDirect3D9_CreateDevice(vid_d3d9, deviceindex, vid_dx9_hal.integer ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF, mainwindow, vid_dx9_softvertex.integer ? D3DCREATE_SOFTWARE_VERTEXPROCESSING : D3DCREATE_HARDWARE_VERTEXPROCESSING, &vid_d3dpresentparameters, &vid_d3d9dev);
1433         }
1434
1435         if (!vid_d3d9dev)
1436         {
1437                 VID_Shutdown();
1438                 return false;
1439         }
1440
1441         IDirect3DDevice9_GetDeviceCaps(vid_d3d9dev, &vid_d3d9caps);
1442
1443         Con_Printf("Using D3D9 device: %s\n", d3d9adapteridentifier.Description);
1444         gl_extensions = "";
1445         gl_platform = "D3D9";
1446         gl_platformextensions = "";
1447
1448         ShowWindow (mainwindow, SW_SHOWDEFAULT);
1449         UpdateWindow (mainwindow);
1450
1451         // now we try to make sure we get the focus on the mode switch, because
1452         // sometimes in some systems we don't.  We grab the foreground, then
1453         // finish setting up, pump all our messages, and sleep for a little while
1454         // to let messages finish bouncing around the system, then we put
1455         // ourselves at the top of the z order, then grab the foreground again,
1456         // Who knows if it helps, but it probably doesn't hurt
1457         SetForegroundWindow (mainwindow);
1458
1459         while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1460         {
1461                 TranslateMessage (&msg);
1462                 DispatchMessage (&msg);
1463         }
1464
1465         Sleep (100);
1466
1467         SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOCOPYBITS);
1468
1469         SetForegroundWindow (mainwindow);
1470
1471         // fix the leftover Alt from any Alt-Tab or the like that switched us away
1472         ClearAllStates ();
1473
1474         gl_renderer = d3d9adapteridentifier.Description;
1475         gl_vendor = d3d9adapteridentifier.Driver;
1476         gl_version = "";
1477         gl_extensions = "";
1478
1479         Con_Printf("D3D9 adapter info:\n");
1480         Con_Printf("Description: %s\n", d3d9adapteridentifier.Description);
1481         Con_Printf("DeviceId: %x\n", (unsigned int)d3d9adapteridentifier.DeviceId);
1482         Con_Printf("DeviceName: %p\n", d3d9adapteridentifier.DeviceName);
1483         Con_Printf("Driver: %s\n", d3d9adapteridentifier.Driver);
1484         Con_Printf("DriverVersion: %08x%08x\n", (unsigned int)d3d9adapteridentifier.DriverVersion.u.HighPart, (unsigned int)d3d9adapteridentifier.DriverVersion.u.LowPart);
1485         Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions);
1486         Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
1487
1488         // clear the extension flags
1489         memset(&vid.support, 0, sizeof(vid.support));
1490         Cvar_SetQuick(&gl_info_extensions, "");
1491
1492         // D3D9 requires BGRA
1493         vid.forcetextype = TEXTYPE_BGRA;
1494
1495         vid.forcevbo = false;
1496         vid.support.arb_depth_texture = true;
1497         vid.support.arb_draw_buffers = vid_d3d9caps.NumSimultaneousRTs > 1;
1498         vid.support.arb_occlusion_query = true; // can't find a cap for this
1499         vid.support.arb_query_buffer_object = true;
1500         vid.support.arb_shadow = true;
1501         vid.support.arb_texture_compression = true;
1502         vid.support.arb_texture_cube_map = true;
1503         vid.support.arb_texture_non_power_of_two = (vid_d3d9caps.TextureCaps & D3DPTEXTURECAPS_POW2) == 0;
1504         vid.support.arb_vertex_buffer_object = true;
1505         vid.support.ext_blend_subtract = true;
1506         vid.support.ext_draw_range_elements = true;
1507         vid.support.ext_framebuffer_object = true;
1508
1509         vid.support.ext_texture_3d = true;
1510         vid.support.ext_texture_compression_s3tc = true;
1511         vid.support.ext_texture_filter_anisotropic = true;
1512         vid.support.ati_separate_stencil = (vid_d3d9caps.StencilCaps & D3DSTENCILCAPS_TWOSIDED) != 0;
1513         vid.support.ext_texture_srgb = false; // FIXME use D3DSAMP_SRGBTEXTURE if CheckDeviceFormat agrees
1514
1515         vid.maxtexturesize_2d = min(vid_d3d9caps.MaxTextureWidth, vid_d3d9caps.MaxTextureHeight);
1516         vid.maxtexturesize_3d = vid_d3d9caps.MaxVolumeExtent;
1517         vid.maxtexturesize_cubemap = vid.maxtexturesize_2d;
1518         vid.texunits = 4;
1519         vid.teximageunits = vid_d3d9caps.MaxSimultaneousTextures;
1520         vid.texarrayunits = 8; // can't find a caps field for this?
1521         vid.max_anisotropy = vid_d3d9caps.MaxAnisotropy;
1522         vid.maxdrawbuffers = vid_d3d9caps.NumSimultaneousRTs;
1523
1524         vid.texunits = bound(4, vid.texunits, MAX_TEXTUREUNITS);
1525         vid.teximageunits = bound(16, vid.teximageunits, MAX_TEXTUREUNITS);
1526         vid.texarrayunits = bound(8, vid.texarrayunits, MAX_TEXTUREUNITS);
1527         Con_DPrintf("Using D3D9.0 rendering path - %i texture matrix, %i texture images, %i texcoords, shadowmapping supported%s\n", vid.texunits, vid.teximageunits, vid.texarrayunits, vid.maxdrawbuffers > 1 ? ", MRT detected (allows prepass deferred lighting)" : "");
1528         vid.renderpath = RENDERPATH_D3D9;
1529         vid.sRGBcapable2D = false;
1530         vid.sRGBcapable3D = true;
1531         vid.useinterleavedarrays = true;
1532
1533         Cvar_SetQuick(&gl_info_vendor, gl_vendor);
1534         Cvar_SetQuick(&gl_info_renderer, gl_renderer);
1535         Cvar_SetQuick(&gl_info_version, gl_version);
1536         Cvar_SetQuick(&gl_info_platform, gl_platform ? gl_platform : "");
1537         Cvar_SetQuick(&gl_info_driver, gl_driver);
1538
1539         // LordHavoc: report supported extensions
1540         Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
1541
1542         // clear to black (loading plaque will be seen over this)
1543         IDirect3DDevice9_Clear(vid_d3d9dev, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
1544         IDirect3DDevice9_BeginScene(vid_d3d9dev);
1545         IDirect3DDevice9_EndScene(vid_d3d9dev);
1546         IDirect3DDevice9_Present(vid_d3d9dev, NULL, NULL, NULL, NULL);
1547         // because the only time we end/begin scene is in VID_Finish, we'd better start a scene now...
1548         IDirect3DDevice9_BeginScene(vid_d3d9dev);
1549         vid_begunscene = true;
1550
1551         //vid_menudrawfn = VID_MenuDraw;
1552         //vid_menukeyfn = VID_MenuKey;
1553         vid_usingmouse = false;
1554         vid_usinghidecursor = false;
1555         vid_usingvsync = false;
1556         vid_hidden = vid_reallyhidden = false;
1557         vid_initialized = true;
1558
1559         IN_StartupMouse ();
1560
1561         return true;
1562 }
1563 #endif
1564
1565 qboolean VID_InitModeSOFT(viddef_mode_t *mode)
1566 {
1567         int i;
1568         HDC hdc;
1569         RECT rect;
1570         MSG msg;
1571         int pixelformat, newpixelformat;
1572         DWORD WindowStyle, ExWindowStyle;
1573         int depth;
1574         DEVMODE thismode;
1575         qboolean foundmode, foundgoodmode;
1576         int bpp = mode->bitsperpixel;
1577         int width = mode->width;
1578         int height = mode->height;
1579         int refreshrate = (int)floor(mode->refreshrate+0.5);
1580         int fullscreen = mode->fullscreen;
1581
1582         if (vid_initialized)
1583                 Sys_Error("VID_InitMode called when video is already initialised");
1584
1585         memset(&gdevmode, 0, sizeof(gdevmode));
1586
1587         vid_isfullscreen = false;
1588         if (fullscreen)
1589         {
1590                 if(vid_forcerefreshrate.integer)
1591                 {
1592                         foundmode = true;
1593                         gdevmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1594                         gdevmode.dmBitsPerPel = bpp;
1595                         gdevmode.dmPelsWidth = width;
1596                         gdevmode.dmPelsHeight = height;
1597                         gdevmode.dmSize = sizeof (gdevmode);
1598                         if(refreshrate)
1599                         {
1600                                 gdevmode.dmFields |= DM_DISPLAYFREQUENCY;
1601                                 gdevmode.dmDisplayFrequency = refreshrate;
1602                         }
1603                 }
1604                 else
1605                 {
1606                         if(refreshrate == 0)
1607                                 refreshrate = initialdevmode.dmDisplayFrequency; // default vid_refreshrate to the rate of the desktop
1608
1609                         foundmode = false;
1610                         foundgoodmode = false;
1611
1612                         thismode.dmSize = sizeof(thismode);
1613                         thismode.dmDriverExtra = 0;
1614                         for(i = 0; EnumDisplaySettings(NULL, i, &thismode); ++i)
1615                         {
1616                                 if(~thismode.dmFields & (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY))
1617                                 {
1618                                         Con_DPrintf("enumerating modes yielded a bogus item... please debug this\n");
1619                                         continue;
1620                                 }
1621                                 if(developer_extra.integer)
1622                                         Con_DPrintf("Found mode %dx%dx%dbpp %dHz... ", (int)thismode.dmPelsWidth, (int)thismode.dmPelsHeight, (int)thismode.dmBitsPerPel, (int)thismode.dmDisplayFrequency);
1623                                 if(thismode.dmBitsPerPel != (DWORD)bpp)
1624                                 {
1625                                         if(developer_extra.integer)
1626                                                 Con_DPrintf("wrong bpp\n");
1627                                         continue;
1628                                 }
1629                                 if(thismode.dmPelsWidth != (DWORD)width)
1630                                 {
1631                                         if(developer_extra.integer)
1632                                                 Con_DPrintf("wrong width\n");
1633                                         continue;
1634                                 }
1635                                 if(thismode.dmPelsHeight != (DWORD)height)
1636                                 {
1637                                         if(developer_extra.integer)
1638                                                 Con_DPrintf("wrong height\n");
1639                                         continue;
1640                                 }
1641
1642                                 if(foundgoodmode)
1643                                 {
1644                                         // if we have a good mode, make sure this mode is better than the previous one, and allowed by the refreshrate
1645                                         if(thismode.dmDisplayFrequency > (DWORD)refreshrate)
1646                                         {
1647                                                 if(developer_extra.integer)
1648                                                         Con_DPrintf("too high refresh rate\n");
1649                                                 continue;
1650                                         }
1651                                         else if(thismode.dmDisplayFrequency <= gdevmode.dmDisplayFrequency)
1652                                         {
1653                                                 if(developer_extra.integer)
1654                                                         Con_DPrintf("doesn't beat previous best match (too low)\n");
1655                                                 continue;
1656                                         }
1657                                 }
1658                                 else if(foundmode)
1659                                 {
1660                                         // we do have one, but it isn't good... make sure it has a lower frequency than the previous one
1661                                         if(thismode.dmDisplayFrequency >= gdevmode.dmDisplayFrequency)
1662                                         {
1663                                                 if(developer_extra.integer)
1664                                                         Con_DPrintf("doesn't beat previous best match (too high)\n");
1665                                                 continue;
1666                                         }
1667                                 }
1668                                 // otherwise, take anything
1669
1670                                 memcpy(&gdevmode, &thismode, sizeof(gdevmode));
1671                                 if(thismode.dmDisplayFrequency <= (DWORD)refreshrate)
1672                                         foundgoodmode = true;
1673                                 else
1674                                 {
1675                                         if(developer_extra.integer)
1676                                                 Con_DPrintf("(out of range)\n");
1677                                 }
1678                                 foundmode = true;
1679                                 if(developer_extra.integer)
1680                                         Con_DPrintf("accepted\n");
1681                         }
1682                 }
1683
1684                 if (!foundmode)
1685                 {
1686                         VID_Shutdown();
1687                         Con_Printf("Unable to find the requested mode %dx%dx%dbpp\n", width, height, bpp);
1688                         return false;
1689                 }
1690                 else if(ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
1691                 {
1692                         VID_Shutdown();
1693                         Con_Printf("Unable to change to requested mode %dx%dx%dbpp\n", width, height, bpp);
1694                         return false;
1695                 }
1696
1697                 vid_isfullscreen = true;
1698                 WindowStyle = WS_POPUP;
1699                 ExWindowStyle = WS_EX_TOPMOST;
1700         }
1701         else
1702         {
1703                 hdc = GetDC (NULL);
1704                 i = GetDeviceCaps(hdc, RASTERCAPS);
1705                 depth = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
1706                 ReleaseDC (NULL, hdc);
1707                 if (i & RC_PALETTE)
1708                 {
1709                         VID_Shutdown();
1710                         Con_Print("Can't run in non-RGB mode\n");
1711                         return false;
1712                 }
1713                 if (bpp > depth)
1714                 {
1715                         VID_Shutdown();
1716                         Con_Print("A higher desktop depth is required to run this video mode\n");
1717                         return false;
1718                 }
1719
1720                 WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
1721                 ExWindowStyle = 0;
1722         }
1723
1724         AdjustWindowBounds(fullscreen, &width, &height, mode, WindowStyle, &rect);
1725
1726         pixelformat = 0;
1727         newpixelformat = 0;
1728         gl_extensions = "";
1729         gl_platformextensions = "";
1730
1731         mainwindow = CreateWindowEx (ExWindowStyle, "DarkPlacesWindowClass", gamename, WindowStyle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, global_hInstance, NULL);
1732         if (!mainwindow)
1733         {
1734                 Con_Printf("CreateWindowEx(%d, %s, %s, %d, %d, %d, %d, %d, %p, %p, %p, %p) failed\n", (int)ExWindowStyle, "DarkPlacesWindowClass", gamename, (int)WindowStyle, (int)(rect.left), (int)(rect.top), (int)(rect.right - rect.left), (int)(rect.bottom - rect.top), (void *)NULL, (void *)NULL, (void *)global_hInstance, (void *)NULL);
1735                 VID_Shutdown();
1736                 return false;
1737         }
1738
1739         baseDC = GetDC(mainwindow);
1740         vid.softpixels = NULL;
1741         memset(&vid_softbmi, 0, sizeof(vid_softbmi));
1742         vid_softbmi.bmiHeader.biSize = sizeof(vid_softbmi.bmiHeader);
1743         vid_softbmi.bmiHeader.biWidth = width;
1744         vid_softbmi.bmiHeader.biHeight = -height; // negative to make a top-down bitmap
1745         vid_softbmi.bmiHeader.biPlanes = 1;
1746         vid_softbmi.bmiHeader.biBitCount = 32;
1747         vid_softbmi.bmiHeader.biCompression = BI_RGB;
1748         vid_softbmi.bmiHeader.biSizeImage = width*height*4;
1749         vid_softbmi.bmiHeader.biClrUsed = 256;
1750         vid_softbmi.bmiHeader.biClrImportant = 256;
1751         vid_softdibhandle = CreateDIBSection(baseDC, &vid_softbmi, DIB_RGB_COLORS, (void **)&vid.softpixels, NULL, 0);
1752         if (!vid_softdibhandle)
1753         {
1754                 Con_Printf("CreateDIBSection failed\n");
1755                 VID_Shutdown();
1756                 return false;
1757         }
1758
1759         vid_softhdc = CreateCompatibleDC(baseDC);
1760         vid_softhdc_backup = SelectObject(vid_softhdc, vid_softdibhandle);
1761         if (!vid_softhdc_backup)
1762         {
1763                 Con_Printf("SelectObject failed\n");
1764                 VID_Shutdown();
1765                 return false;
1766         }
1767 //      ReleaseDC(mainwindow, baseDC);
1768 //      baseDC = NULL;
1769
1770         vid.softdepthpixels = (unsigned int *)calloc(1, mode->width * mode->height * 4);
1771         if (DPSOFTRAST_Init(mode->width, mode->height, vid_soft_threads.integer, vid_soft_interlace.integer, (unsigned int *)vid.softpixels, (unsigned int *)vid.softdepthpixels) < 0)
1772         {
1773                 Con_Printf("Failed to initialize software rasterizer\n");
1774                 VID_Shutdown();
1775                 return false;
1776         }
1777
1778         VID_Soft_SharedSetup();
1779
1780         ShowWindow (mainwindow, SW_SHOWDEFAULT);
1781         UpdateWindow (mainwindow);
1782
1783         // now we try to make sure we get the focus on the mode switch, because
1784         // sometimes in some systems we don't.  We grab the foreground, then
1785         // finish setting up, pump all our messages, and sleep for a little while
1786         // to let messages finish bouncing around the system, then we put
1787         // ourselves at the top of the z order, then grab the foreground again,
1788         // Who knows if it helps, but it probably doesn't hurt
1789         SetForegroundWindow (mainwindow);
1790
1791         while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1792         {
1793                 TranslateMessage (&msg);
1794                 DispatchMessage (&msg);
1795         }
1796
1797         Sleep (100);
1798
1799         SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOCOPYBITS);
1800
1801         SetForegroundWindow (mainwindow);
1802
1803         // fix the leftover Alt from any Alt-Tab or the like that switched us away
1804         ClearAllStates ();
1805
1806         //vid_menudrawfn = VID_MenuDraw;
1807         //vid_menukeyfn = VID_MenuKey;
1808         vid_usingmouse = false;
1809         vid_usinghidecursor = false;
1810         vid_usingvsync = false;
1811         vid_reallyhidden = vid_hidden = false;
1812         vid_initialized = true;
1813
1814         IN_StartupMouse ();
1815
1816         return true;
1817 }
1818
1819 qboolean VID_InitMode(viddef_mode_t *mode)
1820 {
1821 #ifdef SSE_POSSIBLE
1822         if (vid_soft.integer)
1823                 return VID_InitModeSOFT(mode);
1824 #endif
1825 #ifdef SUPPORTD3D
1826 //      if (vid_dx11.integer)
1827 //              return VID_InitModeDX(mode, 11);
1828 //      if (vid_dx10.integer)
1829 //              return VID_InitModeDX(mode, 10);
1830         if (vid_dx9.integer)
1831                 return VID_InitModeDX(mode, 9);
1832 #endif
1833         return VID_InitModeGL(mode);
1834 }
1835
1836
1837 static void IN_Shutdown(void);
1838 void VID_Shutdown (void)
1839 {
1840         qboolean isgl;
1841         if(vid_initialized == false)
1842                 return;
1843
1844         VID_EnableJoystick(false);
1845         VID_SetMouse(false, false, false);
1846
1847         vid_initialized = false;
1848         isgl = gldll != NULL;
1849         IN_Shutdown();
1850         gl_driver[0] = 0;
1851         gl_extensions = "";
1852         gl_platform = "";
1853         gl_platformextensions = "";
1854         if (vid_softhdc)
1855         {
1856                 SelectObject(vid_softhdc, vid_softhdc_backup);
1857                 ReleaseDC(mainwindow, vid_softhdc);
1858         }
1859         vid_softhdc = NULL;
1860         vid_softhdc_backup = NULL;
1861         if (vid_softdibhandle)
1862                 DeleteObject(vid_softdibhandle);
1863         vid_softdibhandle = NULL;
1864         vid.softpixels = NULL;
1865         if (vid.softdepthpixels)
1866                 free(vid.softdepthpixels);
1867         vid.softdepthpixels = NULL;
1868 #ifdef SUPPORTD3D
1869         if (vid_d3d9dev)
1870         {
1871                 if (vid_begunscene)
1872                         IDirect3DDevice9_EndScene(vid_d3d9dev);
1873                 vid_begunscene = false;
1874 //              Cmd_ExecuteString("r_texturestats", src_command, true);
1875 //              Cmd_ExecuteString("memlist", src_command, true);
1876                 IDirect3DDevice9_Release(vid_d3d9dev);
1877         }
1878         vid_d3d9dev = NULL;
1879         if (vid_d3d9)
1880                 IDirect3D9_Release(vid_d3d9);
1881         vid_d3d9 = NULL;
1882 #endif
1883         if (qwglMakeCurrent)
1884                 qwglMakeCurrent(NULL, NULL);
1885         qwglMakeCurrent = NULL;
1886         if (baseRC && qwglDeleteContext)
1887                 qwglDeleteContext(baseRC);
1888         qwglDeleteContext = NULL;
1889         // close the library before we get rid of the window
1890         GL_CloseLibrary();
1891         if (baseDC && mainwindow)
1892                 ReleaseDC(mainwindow, baseDC);
1893         baseDC = NULL;
1894         AppActivate(false, false);
1895         if (mainwindow)
1896                 DestroyWindow(mainwindow);
1897         mainwindow = 0;
1898         if (vid_isfullscreen && isgl)
1899                 ChangeDisplaySettings (NULL, CDS_FULLSCREEN);
1900         vid_isfullscreen = false;
1901 }
1902
1903 void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecursor)
1904 {
1905         static qboolean restore_spi;
1906         static int originalmouseparms[3];
1907
1908         if (!mouseinitialized)
1909                 return;
1910
1911         if (relative)
1912         {
1913                 if (!vid_usingmouse)
1914                 {
1915                         vid_usingmouse = true;
1916                         cl_ignoremousemoves = 2;
1917 #ifdef SUPPORTDIRECTX
1918                         if (dinput && g_pMouse)
1919                         {
1920                                 IDirectInputDevice_Acquire(g_pMouse);
1921                                 dinput_acquired = true;
1922                         }
1923                         else
1924 #endif
1925                         {
1926                                 RECT window_rect;
1927                                 window_rect.left = window_x;
1928                                 window_rect.top = window_y;
1929                                 window_rect.right = window_x + vid.width;
1930                                 window_rect.bottom = window_y + vid.height;
1931
1932                                 // change mouse settings to turn off acceleration
1933 // COMMANDLINEOPTION: Windows GDI Input: -noforcemparms disables setting of mouse parameters (not used with -dinput, windows only)
1934                                 if (!COM_CheckParm ("-noforcemparms") && SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0))
1935                                 {
1936                                         int newmouseparms[3];
1937                                         newmouseparms[0] = 0; // threshold to double movement (only if accel level is >= 1)
1938                                         newmouseparms[1] = 0; // threshold to quadruple movement (only if accel level is >= 2)
1939                                         newmouseparms[2] = 0; // maximum level of acceleration (0 = off)
1940                                         restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0) != FALSE;
1941                                 }
1942                                 else
1943                                         restore_spi = false;
1944                                 SetCursorPos ((window_x + vid.width / 2), (window_y + vid.height / 2));
1945
1946                                 SetCapture (mainwindow);
1947                                 ClipCursor (&window_rect);
1948                         }
1949                 }
1950         }
1951         else
1952         {
1953                 if (vid_usingmouse)
1954                 {
1955                         vid_usingmouse = false;
1956                         cl_ignoremousemoves = 2;
1957 #ifdef SUPPORTDIRECTX
1958                         if (dinput_acquired)
1959                         {
1960                                 IDirectInputDevice_Unacquire(g_pMouse);
1961                                 dinput_acquired = false;
1962                         }
1963                         else
1964 #endif
1965                         {
1966                                 // restore system mouseparms if we changed them
1967                                 if (restore_spi)
1968                                         SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0);
1969                                 restore_spi = false;
1970                                 ClipCursor (NULL);
1971                                 ReleaseCapture ();
1972                         }
1973                 }
1974         }
1975
1976         if (vid_usinghidecursor != hidecursor)
1977         {
1978                 vid_usinghidecursor = hidecursor;
1979                 ShowCursor (!hidecursor);
1980         }
1981 }
1982
1983 void VID_BuildJoyState(vid_joystate_t *joystate)
1984 {
1985         VID_Shared_BuildJoyState_Begin(joystate);
1986         VID_Shared_BuildJoyState_Finish(joystate);
1987 }
1988
1989 void VID_EnableJoystick(qboolean enable)
1990 {
1991         int index = joy_enable.integer > 0 ? joy_index.integer : -1;
1992         qboolean success = false;
1993         int sharedcount = 0;
1994         sharedcount = VID_Shared_SetJoystick(index);
1995         if (index >= 0 && index < sharedcount)
1996                 success = true;
1997
1998         // update cvar containing count of XInput joysticks
1999         if (joy_detected.integer != sharedcount)
2000                 Cvar_SetValueQuick(&joy_detected, sharedcount);
2001
2002         if (joy_active.integer != (success ? 1 : 0))
2003                 Cvar_SetValueQuick(&joy_active, success ? 1 : 0);
2004 }
2005
2006 #ifdef SUPPORTDIRECTX
2007 /*
2008 ===========
2009 IN_InitDInput
2010 ===========
2011 */
2012 static qboolean IN_InitDInput (void)
2013 {
2014     HRESULT             hr;
2015         DIPROPDWORD     dipdw = {
2016                 {
2017                         sizeof(DIPROPDWORD),        // diph.dwSize
2018                         sizeof(DIPROPHEADER),       // diph.dwHeaderSize
2019                         0,                          // diph.dwObj
2020                         DIPH_DEVICE,                // diph.dwHow
2021                 },
2022                 DINPUT_BUFFERSIZE,              // dwData
2023         };
2024
2025         if (!hInstDI)
2026         {
2027                 hInstDI = LoadLibrary("dinput.dll");
2028
2029                 if (hInstDI == NULL)
2030                 {
2031                         Con_Print("Couldn't load dinput.dll\n");
2032                         return false;
2033                 }
2034         }
2035
2036         if (!pDirectInputCreate)
2037         {
2038                 pDirectInputCreate = (HRESULT (__stdcall *)(HINSTANCE,DWORD,LPDIRECTINPUT *,LPUNKNOWN))GetProcAddress(hInstDI,"DirectInputCreateA");
2039
2040                 if (!pDirectInputCreate)
2041                 {
2042                         Con_Print("Couldn't get DI proc addr\n");
2043                         return false;
2044                 }
2045         }
2046
2047 // register with DirectInput and get an IDirectInput to play with.
2048         hr = iDirectInputCreate(global_hInstance, DIRECTINPUT_VERSION, &g_pdi, NULL);
2049
2050         if (FAILED(hr))
2051         {
2052                 return false;
2053         }
2054
2055 // obtain an interface to the system mouse device.
2056 #ifdef __cplusplus
2057         hr = IDirectInput_CreateDevice(g_pdi, GUID_SysMouse, &g_pMouse, NULL);
2058 #else
2059         hr = IDirectInput_CreateDevice(g_pdi, &GUID_SysMouse, &g_pMouse, NULL);
2060 #endif
2061
2062         if (FAILED(hr))
2063         {
2064                 Con_Print("Couldn't open DI mouse device\n");
2065                 return false;
2066         }
2067
2068 // set the data format to "mouse format".
2069         hr = IDirectInputDevice_SetDataFormat(g_pMouse, &c_dfDIMouse);
2070
2071         if (FAILED(hr))
2072         {
2073                 Con_Print("Couldn't set DI mouse format\n");
2074                 return false;
2075         }
2076
2077 // set the cooperativity level.
2078         hr = IDirectInputDevice_SetCooperativeLevel(g_pMouse, mainwindow,
2079                         DISCL_EXCLUSIVE | DISCL_FOREGROUND);
2080
2081         if (FAILED(hr))
2082         {
2083                 Con_Print("Couldn't set DI coop level\n");
2084                 return false;
2085         }
2086
2087
2088 // set the buffer size to DINPUT_BUFFERSIZE elements.
2089 // the buffer size is a DWORD property associated with the device
2090         hr = IDirectInputDevice_SetProperty(g_pMouse, DIPROP_BUFFERSIZE, &dipdw.diph);
2091
2092         if (FAILED(hr))
2093         {
2094                 Con_Print("Couldn't set DI buffersize\n");
2095                 return false;
2096         }
2097
2098         return true;
2099 }
2100 #endif
2101
2102
2103 /*
2104 ===========
2105 IN_StartupMouse
2106 ===========
2107 */
2108 static void IN_StartupMouse (void)
2109 {
2110         if (COM_CheckParm ("-nomouse"))
2111                 return;
2112
2113         mouseinitialized = true;
2114
2115 #ifdef SUPPORTDIRECTX
2116 // COMMANDLINEOPTION: Windows Input: -dinput enables DirectInput for mouse input
2117         if (COM_CheckParm ("-dinput"))
2118                 dinput = IN_InitDInput ();
2119
2120         if (dinput)
2121                 Con_Print("DirectInput initialized\n");
2122         else
2123                 Con_Print("DirectInput not initialized\n");
2124 #endif
2125
2126         mouse_buttons = 10;
2127 }
2128
2129
2130 /*
2131 ===========
2132 IN_MouseMove
2133 ===========
2134 */
2135 static void IN_MouseMove (void)
2136 {
2137         POINT current_pos;
2138
2139         GetCursorPos (&current_pos);
2140         in_windowmouse_x = current_pos.x - window_x;
2141         in_windowmouse_y = current_pos.y - window_y;
2142
2143         if (!vid_usingmouse)
2144                 return;
2145
2146 #ifdef SUPPORTDIRECTX
2147         if (dinput_acquired)
2148         {
2149                 int i;
2150                 DIDEVICEOBJECTDATA      od;
2151                 DWORD                           dwElements;
2152                 HRESULT                         hr;
2153
2154                 for (;;)
2155                 {
2156                         dwElements = 1;
2157
2158                         hr = IDirectInputDevice_GetDeviceData(g_pMouse,
2159                                         sizeof(DIDEVICEOBJECTDATA), &od, &dwElements, 0);
2160
2161                         if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED))
2162                         {
2163                                 IDirectInputDevice_Acquire(g_pMouse);
2164                                 break;
2165                         }
2166
2167                         /* Unable to read data or no data available */
2168                         if (FAILED(hr) || dwElements == 0)
2169                                 break;
2170
2171                         /* Look at the element to see what happened */
2172
2173                         if ((int)od.dwOfs == DIMOFS_X)
2174                                 in_mouse_x += (LONG) od.dwData;
2175                         if ((int)od.dwOfs == DIMOFS_Y)
2176                                 in_mouse_y += (LONG) od.dwData;
2177                         if ((int)od.dwOfs == DIMOFS_Z)
2178                         {
2179                                 if((LONG)od.dwData < 0)
2180                                 {
2181                                         Key_Event(K_MWHEELDOWN, 0, true);
2182                                         Key_Event(K_MWHEELDOWN, 0, false);
2183                                 }
2184                                 else if((LONG)od.dwData > 0)
2185                                 {
2186                                         Key_Event(K_MWHEELUP, 0, true);
2187                                         Key_Event(K_MWHEELUP, 0, false);
2188                                 }
2189                         }
2190                         if ((int)od.dwOfs == DIMOFS_BUTTON0)
2191                                 mstate_di = (mstate_di & ~1) | ((od.dwData & 0x80) >> 7);
2192                         if ((int)od.dwOfs == DIMOFS_BUTTON1)
2193                                 mstate_di = (mstate_di & ~2) | ((od.dwData & 0x80) >> 6);
2194                         if ((int)od.dwOfs == DIMOFS_BUTTON2)
2195                                 mstate_di = (mstate_di & ~4) | ((od.dwData & 0x80) >> 5);
2196                         if ((int)od.dwOfs == DIMOFS_BUTTON3)
2197                                 mstate_di = (mstate_di & ~8) | ((od.dwData & 0x80) >> 4);
2198                 }
2199
2200                 // perform button actions
2201                 for (i=0 ; i<mouse_buttons && i < 16 ; i++)
2202                         if ((mstate_di ^ mouse_oldbuttonstate) & (1<<i))
2203                                 Key_Event (buttonremap[i], 0, (mstate_di & (1<<i)) != 0);
2204                 mouse_oldbuttonstate = mstate_di;
2205         }
2206         else
2207 #endif
2208         {
2209                 in_mouse_x += in_windowmouse_x - (int)(vid.width / 2);
2210                 in_mouse_y += in_windowmouse_y - (int)(vid.height / 2);
2211
2212                 // if the mouse has moved, force it to the center, so there's room to move
2213                 if (in_mouse_x || in_mouse_y)
2214                         SetCursorPos ((window_x + vid.width / 2), (window_y + vid.height / 2));
2215         }
2216 }
2217
2218
2219 /*
2220 ===========
2221 IN_Move
2222 ===========
2223 */
2224 void IN_Move (void)
2225 {
2226         vid_joystate_t joystate;
2227         if (vid_activewindow && !vid_reallyhidden)
2228                 IN_MouseMove ();
2229         VID_EnableJoystick(true);
2230         VID_BuildJoyState(&joystate);
2231         VID_ApplyJoyState(&joystate);
2232 }
2233
2234
2235 static void IN_Init(void)
2236 {
2237         uiWheelMessage = RegisterWindowMessage ( "MSWHEEL_ROLLMSG" );
2238         Cvar_RegisterVariable (&vid_forcerefreshrate);
2239 }
2240
2241 static void IN_Shutdown(void)
2242 {
2243 #ifdef SUPPORTDIRECTX
2244         if (g_pMouse)
2245                 IDirectInputDevice_Release(g_pMouse);
2246         g_pMouse = NULL;
2247
2248         if (g_pdi)
2249                 IDirectInput_Release(g_pdi);
2250         g_pdi = NULL;
2251 #endif
2252 }
2253
2254 vid_mode_t *VID_GetDesktopMode(void)
2255 {
2256         return &desktop_mode;
2257 }
2258
2259 size_t VID_ListModes(vid_mode_t *modes, size_t maxcount)
2260 {
2261         int i;
2262         size_t k;
2263         DEVMODE thismode;
2264
2265         thismode.dmSize = sizeof(thismode);
2266         thismode.dmDriverExtra = 0;
2267         k = 0;
2268         for(i = 0; EnumDisplaySettings(NULL, i, &thismode); ++i)
2269         {
2270                 if(~thismode.dmFields & (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY))
2271                 {
2272                         Con_DPrintf("enumerating modes yielded a bogus item... please debug this\n");
2273                         continue;
2274                 }
2275                 if(k >= maxcount)
2276                         break;
2277                 modes[k].width = thismode.dmPelsWidth;
2278                 modes[k].height = thismode.dmPelsHeight;
2279                 modes[k].bpp = thismode.dmBitsPerPel;
2280                 modes[k].refreshrate = thismode.dmDisplayFrequency;
2281                 modes[k].pixelheight_num = 1;
2282                 modes[k].pixelheight_denom = 1; // Win32 apparently does not provide this (FIXME)
2283                 ++k;
2284         }
2285         return k;
2286 }