1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20// gl_vidnt.c -- NT GL vid component
21
22#include "quakedef.h"
23#include "winquake.h"
24#include "resource.h"
25#include <commctrl.h>
26
27#define MAX_MODE_LIST	30
28#define VID_ROW_SIZE	3
29#define WARP_WIDTH		320
30#define WARP_HEIGHT		200
31#define MAXWIDTH		10000
32#define MAXHEIGHT		10000
33#define BASEWIDTH		320
34#define BASEHEIGHT		200
35
36#define MODE_WINDOWED			0
37#define NO_MODE					(MODE_WINDOWED - 1)
38#define MODE_FULLSCREEN_DEFAULT	(MODE_WINDOWED + 1)
39
40typedef struct {
41	modestate_t	type;
42	int			width;
43	int			height;
44	int			modenum;
45	int			dib;
46	int			fullscreen;
47	int			bpp;
48	int			halfscreen;
49	char		modedesc[17];
50} vmode_t;
51
52typedef struct {
53	int			width;
54	int			height;
55} lmode_t;
56
57lmode_t	lowresmodes[] = {
58	{320, 200},
59	{320, 240},
60	{400, 300},
61	{512, 384},
62};
63
64const char *gl_vendor;
65const char *gl_renderer;
66const char *gl_version;
67const char *gl_extensions;
68
69qboolean		DDActive;
70qboolean		scr_skipupdate;
71
72static vmode_t	modelist[MAX_MODE_LIST];
73static int		nummodes;
74static vmode_t	*pcurrentmode;
75static vmode_t	badmode;
76
77static DEVMODE	gdevmode;
78static qboolean	vid_initialized = false;
79static qboolean	windowed, leavecurrentmode;
80static qboolean vid_canalttab = false;
81static qboolean vid_wassuspended = false;
82static int		windowed_mouse;
83extern qboolean	mouseactive;  // from in_win.c
84static HICON	hIcon;
85
86int			DIBWidth, DIBHeight;
87RECT		WindowRect;
88DWORD		WindowStyle, ExWindowStyle;
89
90HWND	mainwindow, dibwindow;
91
92int			vid_modenum = NO_MODE;
93int			vid_realmode;
94int			vid_default = MODE_WINDOWED;
95static int	windowed_default;
96unsigned char	vid_curpal[256*3];
97static qboolean fullsbardraw = false;
98
99static float vid_gamma = 1.0;
100
101HGLRC	baseRC;
102HDC		maindc;
103
104glvert_t glv;
105
106cvar_t	gl_ztrick = {"gl_ztrick","1"};
107
108HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow);
109
110viddef_t	vid;				// global video state
111
112unsigned short	d_8to16table[256];
113unsigned	d_8to24table[256];
114unsigned char d_15to8table[65536];
115
116float		gldepthmin, gldepthmax;
117
118modestate_t	modestate = MS_UNINIT;
119
120void VID_MenuDraw (void);
121void VID_MenuKey (int key);
122
123LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
124void AppActivate(BOOL fActive, BOOL minimize);
125char *VID_GetModeDescription (int mode);
126void ClearAllStates (void);
127void VID_UpdateWindowStatus (void);
128void GL_Init (void);
129
130PROC glArrayElementEXT;
131PROC glColorPointerEXT;
132PROC glTexCoordPointerEXT;
133PROC glVertexPointerEXT;
134
135typedef void (APIENTRY *lp3DFXFUNC) (int, int, int, int, int, const void*);
136lp3DFXFUNC glColorTableEXT;
137qboolean is8bit = false;
138qboolean isPermedia = false;
139qboolean gl_mtexable = false;
140
141//====================================
142
143cvar_t		vid_mode = {"vid_mode","0", false};
144// Note that 0 is MODE_WINDOWED
145cvar_t		_vid_default_mode = {"_vid_default_mode","0", true};
146// Note that 3 is MODE_FULLSCREEN_DEFAULT
147cvar_t		_vid_default_mode_win = {"_vid_default_mode_win","3", true};
148cvar_t		vid_wait = {"vid_wait","0"};
149cvar_t		vid_nopageflip = {"vid_nopageflip","0", true};
150cvar_t		_vid_wait_override = {"_vid_wait_override", "0", true};
151cvar_t		vid_config_x = {"vid_config_x","800", true};
152cvar_t		vid_config_y = {"vid_config_y","600", true};
153cvar_t		vid_stretch_by_2 = {"vid_stretch_by_2","1", true};
154cvar_t		_windowed_mouse = {"_windowed_mouse","1", true};
155
156int			window_center_x, window_center_y, window_x, window_y, window_width, window_height;
157RECT		window_rect;
158
159// direct draw software compatability stuff
160
161void VID_HandlePause (qboolean pause)
162{
163}
164
165void VID_ForceLockState (int lk)
166{
167}
168
169void VID_LockBuffer (void)
170{
171}
172
173void VID_UnlockBuffer (void)
174{
175}
176
177int VID_ForceUnlockedAndReturnState (void)
178{
179	return 0;
180}
181
182void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
183{
184}
185
186void D_EndDirectRect (int x, int y, int width, int height)
187{
188}
189
190
191void CenterWindow(HWND hWndCenter, int width, int height, BOOL lefttopjustify)
192{
193    RECT    rect;
194    int     CenterX, CenterY;
195
196	CenterX = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
197	CenterY = (GetSystemMetrics(SM_CYSCREEN) - height) / 2;
198	if (CenterX > CenterY*2)
199		CenterX >>= 1;	// dual screens
200	CenterX = (CenterX < 0) ? 0: CenterX;
201	CenterY = (CenterY < 0) ? 0: CenterY;
202	SetWindowPos (hWndCenter, NULL, CenterX, CenterY, 0, 0,
203			SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME);
204}
205
206qboolean VID_SetWindowedMode (int modenum)
207{
208	HDC				hdc;
209	int				lastmodestate, width, height;
210	RECT			rect;
211
212	lastmodestate = modestate;
213
214	WindowRect.top = WindowRect.left = 0;
215
216	WindowRect.right = modelist[modenum].width;
217	WindowRect.bottom = modelist[modenum].height;
218
219	DIBWidth = modelist[modenum].width;
220	DIBHeight = modelist[modenum].height;
221
222	WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU |
223				  WS_MINIMIZEBOX;
224	ExWindowStyle = 0;
225
226	rect = WindowRect;
227	AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0);
228
229	width = rect.right - rect.left;
230	height = rect.bottom - rect.top;
231
232	// Create the DIB window
233	dibwindow = CreateWindowEx (
234		 ExWindowStyle,
235		 "WinQuake",
236		 "GLQuake",
237		 WindowStyle,
238		 rect.left, rect.top,
239		 width,
240		 height,
241		 NULL,
242		 NULL,
243		 global_hInstance,
244		 NULL);
245
246	if (!dibwindow)
247		Sys_Error ("Couldn't create DIB window");
248
249	// Center and show the DIB window
250	CenterWindow(dibwindow, WindowRect.right - WindowRect.left,
251				 WindowRect.bottom - WindowRect.top, false);
252
253	ShowWindow (dibwindow, SW_SHOWDEFAULT);
254	UpdateWindow (dibwindow);
255
256	modestate = MS_WINDOWED;
257
258// because we have set the background brush for the window to NULL
259// (to avoid flickering when re-sizing the window on the desktop),
260// we clear the window to black when created, otherwise it will be
261// empty while Quake starts up.
262	hdc = GetDC(dibwindow);
263	PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS);
264	ReleaseDC(dibwindow, hdc);
265
266	if (vid.conheight > modelist[modenum].height)
267		vid.conheight = modelist[modenum].height;
268	if (vid.conwidth > modelist[modenum].width)
269		vid.conwidth = modelist[modenum].width;
270	vid.width = vid.conwidth;
271	vid.height = vid.conheight;
272
273	vid.numpages = 2;
274
275	mainwindow = dibwindow;
276
277	SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon);
278	SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon);
279
280	return true;
281}
282
283
284qboolean VID_SetFullDIBMode (int modenum)
285{
286	HDC				hdc;
287	int				lastmodestate, width, height;
288	RECT			rect;
289
290	if (!leavecurrentmode)
291	{
292		gdevmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
293		gdevmode.dmBitsPerPel = modelist[modenum].bpp;
294		gdevmode.dmPelsWidth = modelist[modenum].width <<
295							   modelist[modenum].halfscreen;
296		gdevmode.dmPelsHeight = modelist[modenum].height;
297		gdevmode.dmSize = sizeof (gdevmode);
298
299		if (ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
300			Sys_Error ("Couldn't set fullscreen DIB mode");
301	}
302
303	lastmodestate = modestate;
304	modestate = MS_FULLDIB;
305
306	WindowRect.top = WindowRect.left = 0;
307
308	WindowRect.right = modelist[modenum].width;
309	WindowRect.bottom = modelist[modenum].height;
310
311	DIBWidth = modelist[modenum].width;
312	DIBHeight = modelist[modenum].height;
313
314	WindowStyle = WS_POPUP;
315	ExWindowStyle = 0;
316
317	rect = WindowRect;
318	AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0);
319
320	width = rect.right - rect.left;
321	height = rect.bottom - rect.top;
322
323	// Create the DIB window
324	dibwindow = CreateWindowEx (
325		 ExWindowStyle,
326		 "WinQuake",
327		 "GLQuake",
328		 WindowStyle,
329		 rect.left, rect.top,
330		 width,
331		 height,
332		 NULL,
333		 NULL,
334		 global_hInstance,
335		 NULL);
336
337	if (!dibwindow)
338		Sys_Error ("Couldn't create DIB window");
339
340	ShowWindow (dibwindow, SW_SHOWDEFAULT);
341	UpdateWindow (dibwindow);
342
343	// Because we have set the background brush for the window to NULL
344	// (to avoid flickering when re-sizing the window on the desktop), we
345	// clear the window to black when created, otherwise it will be
346	// empty while Quake starts up.
347	hdc = GetDC(dibwindow);
348	PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS);
349	ReleaseDC(dibwindow, hdc);
350
351	if (vid.conheight > modelist[modenum].height)
352		vid.conheight = modelist[modenum].height;
353	if (vid.conwidth > modelist[modenum].width)
354		vid.conwidth = modelist[modenum].width;
355	vid.width = vid.conwidth;
356	vid.height = vid.conheight;
357
358	vid.numpages = 2;
359
360// needed because we're not getting WM_MOVE messages fullscreen on NT
361	window_x = 0;
362	window_y = 0;
363
364	mainwindow = dibwindow;
365
366	SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon);
367	SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon);
368
369	return true;
370}
371
372
373int VID_SetMode (int modenum, unsigned char *palette)
374{
375	int				original_mode, temp;
376	qboolean		stat;
377    MSG				msg;
378	HDC				hdc;
379
380	if ((windowed && (modenum != 0)) ||
381		(!windowed && (modenum < 1)) ||
382		(!windowed && (modenum >= nummodes)))
383	{
384		Sys_Error ("Bad video mode\n");
385	}
386
387// so Con_Printfs don't mess us up by forcing vid and snd updates
388	temp = scr_disabled_for_loading;
389	scr_disabled_for_loading = true;
390
391	CDAudio_Pause ();
392
393	if (vid_modenum == NO_MODE)
394		original_mode = windowed_default;
395	else
396		original_mode = vid_modenum;
397
398	// Set either the fullscreen or windowed mode
399	if (modelist[modenum].type == MS_WINDOWED)
400	{
401		if (_windowed_mouse.value && key_dest == key_game)
402		{
403			stat = VID_SetWindowedMode(modenum);
404			IN_ActivateMouse ();
405			IN_HideMouse ();
406		}
407		else
408		{
409			IN_DeactivateMouse ();
410			IN_ShowMouse ();
411			stat = VID_SetWindowedMode(modenum);
412		}
413	}
414	else if (modelist[modenum].type == MS_FULLDIB)
415	{
416		stat = VID_SetFullDIBMode(modenum);
417		IN_ActivateMouse ();
418		IN_HideMouse ();
419	}
420	else
421	{
422		Sys_Error ("VID_SetMode: Bad mode type in modelist");
423	}
424
425	window_width = DIBWidth;
426	window_height = DIBHeight;
427	VID_UpdateWindowStatus ();
428
429	CDAudio_Resume ();
430	scr_disabled_for_loading = temp;
431
432	if (!stat)
433	{
434		Sys_Error ("Couldn't set video mode");
435	}
436
437// now we try to make sure we get the focus on the mode switch, because
438// sometimes in some systems we don't.  We grab the foreground, then
439// finish setting up, pump all our messages, and sleep for a little while
440// to let messages finish bouncing around the system, then we put
441// ourselves at the top of the z order, then grab the foreground again,
442// Who knows if it helps, but it probably doesn't hurt
443	SetForegroundWindow (mainwindow);
444	VID_SetPalette (palette);
445	vid_modenum = modenum;
446	Cvar_SetValue ("vid_mode", (float)vid_modenum);
447
448	while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
449	{
450      	TranslateMessage (&msg);
451      	DispatchMessage (&msg);
452	}
453
454	Sleep (100);
455
456	SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0,
457				  SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW |
458				  SWP_NOCOPYBITS);
459
460	SetForegroundWindow (mainwindow);
461
462// fix the leftover Alt from any Alt-Tab or the like that switched us away
463	ClearAllStates ();
464
465	if (!msg_suppress_1)
466		Con_SafePrintf ("Video mode %s initialized.\n", VID_GetModeDescription (vid_modenum));
467
468	VID_SetPalette (palette);
469
470	vid.recalc_refdef = 1;
471
472	return true;
473}
474
475
476/*
477================
478VID_UpdateWindowStatus
479================
480*/
481void VID_UpdateWindowStatus (void)
482{
483
484	window_rect.left = window_x;
485	window_rect.top = window_y;
486	window_rect.right = window_x + window_width;
487	window_rect.bottom = window_y + window_height;
488	window_center_x = (window_rect.left + window_rect.right) / 2;
489	window_center_y = (window_rect.top + window_rect.bottom) / 2;
490
491	IN_UpdateClipCursor ();
492}
493
494
495//====================================
496
497BINDTEXFUNCPTR bindTexFunc;
498
499#define TEXTURE_EXT_STRING "GL_EXT_texture_object"
500
501
502void CheckTextureExtensions (void)
503{
504	char		*tmp;
505	qboolean	texture_ext;
506	HINSTANCE	hInstGL;
507
508	texture_ext = FALSE;
509	/* check for texture extension */
510	tmp = (unsigned char *)glGetString(GL_EXTENSIONS);
511	while (*tmp)
512	{
513		if (strncmp((const char*)tmp, TEXTURE_EXT_STRING, strlen(TEXTURE_EXT_STRING)) == 0)
514			texture_ext = TRUE;
515		tmp++;
516	}
517
518	if (!texture_ext || COM_CheckParm ("-gl11") )
519	{
520		hInstGL = LoadLibrary("opengl32.dll");
521
522		if (hInstGL == NULL)
523			Sys_Error ("Couldn't load opengl32.dll\n");
524
525		bindTexFunc = (void *)GetProcAddress(hInstGL,"glBindTexture");
526
527		if (!bindTexFunc)
528			Sys_Error ("No texture objects!");
529		return;
530	}
531
532/* load library and get procedure adresses for texture extension API */
533	if ((bindTexFunc = (BINDTEXFUNCPTR)
534		wglGetProcAddress((LPCSTR) "glBindTextureEXT")) == NULL)
535	{
536		Sys_Error ("GetProcAddress for BindTextureEXT failed");
537		return;
538	}
539}
540
541void CheckArrayExtensions (void)
542{
543	char		*tmp;
544
545	/* check for texture extension */
546	tmp = (unsigned char *)glGetString(GL_EXTENSIONS);
547	while (*tmp)
548	{
549		if (strncmp((const char*)tmp, "GL_EXT_vertex_array", strlen("GL_EXT_vertex_array")) == 0)
550		{
551			if (
552((glArrayElementEXT = wglGetProcAddress("glArrayElementEXT")) == NULL) ||
553((glColorPointerEXT = wglGetProcAddress("glColorPointerEXT")) == NULL) ||
554((glTexCoordPointerEXT = wglGetProcAddress("glTexCoordPointerEXT")) == NULL) ||
555((glVertexPointerEXT = wglGetProcAddress("glVertexPointerEXT")) == NULL) )
556			{
557				Sys_Error ("GetProcAddress for vertex extension failed");
558				return;
559			}
560			return;
561		}
562		tmp++;
563	}
564
565	Sys_Error ("Vertex array extension not present");
566}
567
568//int		texture_mode = GL_NEAREST;
569//int		texture_mode = GL_NEAREST_MIPMAP_NEAREST;
570//int		texture_mode = GL_NEAREST_MIPMAP_LINEAR;
571int		texture_mode = GL_LINEAR;
572//int		texture_mode = GL_LINEAR_MIPMAP_NEAREST;
573//int		texture_mode = GL_LINEAR_MIPMAP_LINEAR;
574
575int		texture_extension_number = 1;
576
577#ifdef _WIN32
578void CheckMultiTextureExtensions(void)
579{
580	if (strstr(gl_extensions, "GL_SGIS_multitexture ") && !COM_CheckParm("-nomtex")) {
581		Con_Printf("Multitexture extensions found.\n");
582		qglMTexCoord2fSGIS = (void *) wglGetProcAddress("glMTexCoord2fSGIS");
583		qglSelectTextureSGIS = (void *) wglGetProcAddress("glSelectTextureSGIS");
584		gl_mtexable = true;
585	}
586}
587#else
588void CheckMultiTextureExtensions(void)
589{
590		gl_mtexable = true;
591}
592#endif
593
594/*
595===============
596GL_Init
597===============
598*/
599void GL_Init (void)
600{
601	gl_vendor = glGetString (GL_VENDOR);
602	Con_Printf ("GL_VENDOR: %s\n", gl_vendor);
603	gl_renderer = glGetString (GL_RENDERER);
604	Con_Printf ("GL_RENDERER: %s\n", gl_renderer);
605
606	gl_version = glGetString (GL_VERSION);
607	Con_Printf ("GL_VERSION: %s\n", gl_version);
608	gl_extensions = glGetString (GL_EXTENSIONS);
609	Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions);
610
611//	Con_Printf ("%s %s\n", gl_renderer, gl_version);
612
613    if (strnicmp(gl_renderer,"PowerVR",7)==0)
614         fullsbardraw = true;
615
616    if (strnicmp(gl_renderer,"Permedia",8)==0)
617         isPermedia = true;
618
619	CheckTextureExtensions ();
620	CheckMultiTextureExtensions ();
621
622	glClearColor (1,0,0,0);
623	glCullFace(GL_FRONT);
624	glEnable(GL_TEXTURE_2D);
625
626	glEnable(GL_ALPHA_TEST);
627	glAlphaFunc(GL_GREATER, 0.666);
628
629	glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
630	glShadeModel (GL_FLAT);
631
632	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
633	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
634	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
635	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
636
637	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
638
639//	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
640	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
641
642#if 0
643	CheckArrayExtensions ();
644
645	glEnable (GL_VERTEX_ARRAY_EXT);
646	glEnable (GL_TEXTURE_COORD_ARRAY_EXT);
647	glVertexPointerEXT (3, GL_FLOAT, 0, 0, &glv.x);
648	glTexCoordPointerEXT (2, GL_FLOAT, 0, 0, &glv.s);
649	glColorPointerEXT (3, GL_FLOAT, 0, 0, &glv.r);
650#endif
651}
652
653/*
654=================
655GL_BeginRendering
656
657=================
658*/
659void GL_BeginRendering (int *x, int *y, int *width, int *height)
660{
661	extern cvar_t gl_clear;
662
663	*x = *y = 0;
664	*width = WindowRect.right - WindowRect.left;
665	*height = WindowRect.bottom - WindowRect.top;
666
667//    if (!wglMakeCurrent( maindc, baseRC ))
668//		Sys_Error ("wglMakeCurrent failed");
669
670//	glViewport (*x, *y, *width, *height);
671}
672
673
674void GL_EndRendering (void)
675{
676	if (!scr_skipupdate || block_drawing)
677		SwapBuffers(maindc);
678
679// handle the mouse state when windowed if that's changed
680	if (modestate == MS_WINDOWED)
681	{
682		if (!_windowed_mouse.value) {
683			if (windowed_mouse)	{
684				IN_DeactivateMouse ();
685				IN_ShowMouse ();
686				windowed_mouse = false;
687			}
688		} else {
689			windowed_mouse = true;
690			if (key_dest == key_game && !mouseactive && ActiveApp) {
691				IN_ActivateMouse ();
692				IN_HideMouse ();
693			} else if (mouseactive && key_dest != key_game) {
694				IN_DeactivateMouse ();
695				IN_ShowMouse ();
696			}
697		}
698	}
699	if (fullsbardraw)
700		Sbar_Changed();
701}
702
703void	VID_SetPalette (unsigned char *palette)
704{
705	byte	*pal;
706	unsigned r,g,b;
707	unsigned v;
708	int     r1,g1,b1;
709	int		j,k,l,m;
710	unsigned short i;
711	unsigned	*table;
712	FILE *f;
713	char s[255];
714	HWND hDlg, hProgress;
715	float gamma;
716
717//
718// 8 8 8 encoding
719//
720	pal = palette;
721	table = d_8to24table;
722	for (i=0 ; i<256 ; i++)
723	{
724		r = pal[0];
725		g = pal[1];
726		b = pal[2];
727		pal += 3;
728
729//		v = (255<<24) + (r<<16) + (g<<8) + (b<<0);
730//		v = (255<<0) + (r<<8) + (g<<16) + (b<<24);
731		v = (255<<24) + (r<<0) + (g<<8) + (b<<16);
732		*table++ = v;
733	}
734	d_8to24table[255] &= 0xffffff;	// 255 is transparent
735
736	// JACK: 3D distance calcs - k is last closest, l is the distance.
737	// FIXME: Precalculate this and cache to disk.
738	for (i=0; i < (1<<15); i++) {
739		/* Maps
740			000000000000000
741			000000000011111 = Red  = 0x1F
742			000001111100000 = Blue = 0x03E0
743			111110000000000 = Grn  = 0x7C00
744		*/
745		r = ((i & 0x1F) << 3)+4;
746		g = ((i & 0x03E0) >> 2)+4;
747		b = ((i & 0x7C00) >> 7)+4;
748		pal = (unsigned char *)d_8to24table;
749		for (v=0,k=0,l=10000*10000; v<256; v++,pal+=4) {
750			r1 = r-pal[0];
751			g1 = g-pal[1];
752			b1 = b-pal[2];
753			j = (r1*r1)+(g1*g1)+(b1*b1);
754			if (j<l) {
755				k=v;
756				l=j;
757			}
758		}
759		d_15to8table[i]=k;
760	}
761}
762
763BOOL	gammaworks;
764
765void	VID_ShiftPalette (unsigned char *palette)
766{
767	extern	byte ramps[3][256];
768
769//	VID_SetPalette (palette);
770
771//	gammaworks = SetDeviceGammaRamp (maindc, ramps);
772}
773
774
775void VID_SetDefaultMode (void)
776{
777	IN_DeactivateMouse ();
778}
779
780
781void	VID_Shutdown (void)
782{
783   	HGLRC hRC;
784   	HDC	  hDC;
785
786	if (vid_initialized)
787	{
788		vid_canalttab = false;
789		hRC = wglGetCurrentContext();
790    	hDC = wglGetCurrentDC();
791
792    	wglMakeCurrent(NULL, NULL);
793
794    	if (hRC)
795    	    wglDeleteContext(hRC);
796
797		if (hDC && dibwindow)
798			ReleaseDC(dibwindow, hDC);
799
800		if (modestate == MS_FULLDIB)
801			ChangeDisplaySettings (NULL, 0);
802
803		if (maindc && dibwindow)
804			ReleaseDC (dibwindow, maindc);
805
806		AppActivate(false, false);
807	}
808}
809
810
811//==========================================================================
812
813
814BOOL bSetupPixelFormat(HDC hDC)
815{
816    static PIXELFORMATDESCRIPTOR pfd = {
817	sizeof(PIXELFORMATDESCRIPTOR),	// size of this pfd
818	1,				// version number
819	PFD_DRAW_TO_WINDOW 		// support window
820	|  PFD_SUPPORT_OPENGL 	// support OpenGL
821	|  PFD_DOUBLEBUFFER ,	// double buffered
822	PFD_TYPE_RGBA,			// RGBA type
823	24,				// 24-bit color depth
824	0, 0, 0, 0, 0, 0,		// color bits ignored
825	0,				// no alpha buffer
826	0,				// shift bit ignored
827	0,				// no accumulation buffer
828	0, 0, 0, 0, 			// accum bits ignored
829	32,				// 32-bit z-buffer
830	0,				// no stencil buffer
831	0,				// no auxiliary buffer
832	PFD_MAIN_PLANE,			// main layer
833	0,				// reserved
834	0, 0, 0				// layer masks ignored
835    };
836    int pixelformat;
837
838    if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 )
839    {
840        MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);
841        return FALSE;
842    }
843
844    if (SetPixelFormat(hDC, pixelformat, &pfd) == FALSE)
845    {
846        MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);
847        return FALSE;
848    }
849
850    return TRUE;
851}
852
853
854
855byte        scantokey[128] =
856					{
857//  0           1       2       3       4       5       6       7
858//  8           9       A       B       C       D       E       F
859	0  ,    27,     '1',    '2',    '3',    '4',    '5',    '6',
860	'7',    '8',    '9',    '0',    '-',    '=',    K_BACKSPACE, 9, // 0
861	'q',    'w',    'e',    'r',    't',    'y',    'u',    'i',
862	'o',    'p',    '[',    ']',    13 ,    K_CTRL,'a',  's',      // 1
863	'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';',
864	'\'' ,    '`',    K_SHIFT,'\\',  'z',    'x',    'c',    'v',      // 2
865	'b',    'n',    'm',    ',',    '.',    '/',    K_SHIFT,'*',
866	K_ALT,' ',   0  ,    K_F1, K_F2, K_F3, K_F4, K_F5,   // 3
867	K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE  ,    0  , K_HOME,
868	K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+',K_END, //4
869	K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0,             0,              K_F11,
870	K_F12,0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 5
871	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,
872	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 6
873	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,
874	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0         // 7
875					};
876
877byte        shiftscantokey[128] =
878					{
879//  0           1       2       3       4       5       6       7
880//  8           9       A       B       C       D       E       F
881	0  ,    27,     '!',    '@',    '#',    '$',    '%',    '^',
882	'&',    '*',    '(',    ')',    '_',    '+',    K_BACKSPACE, 9, // 0
883	'Q',    'W',    'E',    'R',    'T',    'Y',    'U',    'I',
884	'O',    'P',    '{',    '}',    13 ,    K_CTRL,'A',  'S',      // 1
885	'D',    'F',    'G',    'H',    'J',    'K',    'L',    ':',
886	'"' ,    '~',    K_SHIFT,'|',  'Z',    'X',    'C',    'V',      // 2
887	'B',    'N',    'M',    '<',    '>',    '?',    K_SHIFT,'*',
888	K_ALT,' ',   0  ,    K_F1, K_F2, K_F3, K_F4, K_F5,   // 3
889	K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE  ,    0  , K_HOME,
890	K_UPARROW,K_PGUP,'_',K_LEFTARROW,'%',K_RIGHTARROW,'+',K_END, //4
891	K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0,             0,              K_F11,
892	K_F12,0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 5
893	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,
894	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 6
895	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,
896	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0         // 7
897					};
898
899
900/*
901=======
902MapKey
903
904Map from windows to quake keynums
905=======
906*/
907int MapKey (int key)
908{
909	key = (key>>16)&255;
910	if (key > 127)
911		return 0;
912	if (scantokey[key] == 0)
913		Con_DPrintf("key 0x%02x has no translation\n", key);
914	return scantokey[key];
915}
916
917/*
918===================================================================
919
920MAIN WINDOW
921
922===================================================================
923*/
924
925/*
926================
927ClearAllStates
928================
929*/
930void ClearAllStates (void)
931{
932	int		i;
933
934// send an up event for each key, to make sure the server clears them all
935	for (i=0 ; i<256 ; i++)
936	{
937		Key_Event (i, false);
938	}
939
940	Key_ClearStates ();
941	IN_ClearStates ();
942}
943
944void AppActivate(BOOL fActive, BOOL minimize)
945/****************************************************************************
946*
947* Function:     AppActivate
948* Parameters:   fActive - True if app is activating
949*
950* Description:  If the application is activating, then swap the system
951*               into SYSPAL_NOSTATIC mode so that our palettes will display
952*               correctly.
953*
954****************************************************************************/
955{
956	MSG msg;
957    HDC			hdc;
958    int			i, t;
959	static BOOL	sound_active;
960
961	ActiveApp = fActive;
962	Minimized = minimize;
963
964// enable/disable sound on focus gain/loss
965	if (!ActiveApp && sound_active)
966	{
967		S_BlockSound ();
968		sound_active = false;
969	}
970	else if (ActiveApp && !sound_active)
971	{
972		S_UnblockSound ();
973		sound_active = true;
974	}
975
976	if (fActive)
977	{
978		if (modestate == MS_FULLDIB)
979		{
980			IN_ActivateMouse ();
981			IN_HideMouse ();
982			if (vid_canalttab && vid_wassuspended) {
983				vid_wassuspended = false;
984				ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN);
985				ShowWindow(mainwindow, SW_SHOWNORMAL);
986			}
987		}
988		else if ((modestate == MS_WINDOWED) && _windowed_mouse.value && key_dest == key_game)
989		{
990			IN_ActivateMouse ();
991			IN_HideMouse ();
992		}
993	}
994
995	if (!fActive)
996	{
997		if (modestate == MS_FULLDIB)
998		{
999			IN_DeactivateMouse ();
1000			IN_ShowMouse ();
1001			if (vid_canalttab) {
1002				ChangeDisplaySettings (NULL, 0);
1003				vid_wassuspended = true;
1004			}
1005		}
1006		else if ((modestate == MS_WINDOWED) && _windowed_mouse.value)
1007		{
1008			IN_DeactivateMouse ();
1009			IN_ShowMouse ();
1010		}
1011	}
1012}
1013
1014
1015/* main window procedure */
1016LONG WINAPI MainWndProc (
1017    HWND    hWnd,
1018    UINT    uMsg,
1019    WPARAM  wParam,
1020    LPARAM  lParam)
1021{
1022    LONG    lRet = 1;
1023	int		fwKeys, xPos, yPos, fActive, fMinimized, temp;
1024	extern unsigned int uiWheelMessage;
1025
1026	if ( uMsg == uiWheelMessage )
1027		uMsg = WM_MOUSEWHEEL;
1028
1029    switch (uMsg)
1030    {
1031		case WM_KILLFOCUS:
1032			if (modestate == MS_FULLDIB)
1033				ShowWindow(mainwindow, SW_SHOWMINNOACTIVE);
1034			break;
1035
1036		case WM_CREATE:
1037			break;
1038
1039		case WM_MOVE:
1040			window_x = (int) LOWORD(lParam);
1041			window_y = (int) HIWORD(lParam);
1042			VID_UpdateWindowStatus ();
1043			break;
1044
1045		case WM_KEYDOWN:
1046		case WM_SYSKEYDOWN:
1047			Key_Event (MapKey(lParam), true);
1048			break;
1049
1050		case WM_KEYUP:
1051		case WM_SYSKEYUP:
1052			Key_Event (MapKey(lParam), false);
1053			break;
1054
1055		case WM_SYSCHAR:
1056		// keep Alt-Space from happening
1057			break;
1058
1059	// this is complicated because Win32 seems to pack multiple mouse events into
1060	// one update sometimes, so we always check all states and look for events
1061		case WM_LBUTTONDOWN:
1062		case WM_LBUTTONUP:
1063		case WM_RBUTTONDOWN:
1064		case WM_RBUTTONUP:
1065		case WM_MBUTTONDOWN:
1066		case WM_MBUTTONUP:
1067		case WM_MOUSEMOVE:
1068			temp = 0;
1069
1070			if (wParam & MK_LBUTTON)
1071				temp |= 1;
1072
1073			if (wParam & MK_RBUTTON)
1074				temp |= 2;
1075
1076			if (wParam & MK_MBUTTON)
1077				temp |= 4;
1078
1079			IN_MouseEvent (temp);
1080
1081			break;
1082
1083		// JACK: This is the mouse wheel with the Intellimouse
1084		// Its delta is either positive or neg, and we generate the proper
1085		// Event.
1086		case WM_MOUSEWHEEL:
1087			if ((short) HIWORD(wParam) > 0) {
1088				Key_Event(K_MWHEELUP, true);
1089				Key_Event(K_MWHEELUP, false);
1090			} else {
1091				Key_Event(K_MWHEELDOWN, true);
1092				Key_Event(K_MWHEELDOWN, false);
1093			}
1094			break;
1095
1096    	case WM_SIZE:
1097            break;
1098
1099   	    case WM_CLOSE:
1100			if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit",
1101						MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES)
1102			{
1103				Sys_Quit ();
1104			}
1105
1106	        break;
1107
1108		case WM_ACTIVATE:
1109			fActive = LOWORD(wParam);
1110			fMinimized = (BOOL) HIWORD(wParam);
1111			AppActivate(!(fActive == WA_INACTIVE), fMinimized);
1112
1113		// fix the leftover Alt from any Alt-Tab or the like that switched us away
1114			ClearAllStates ();
1115
1116			break;
1117
1118   	    case WM_DESTROY:
1119        {
1120			if (dibwindow)
1121				DestroyWindow (dibwindow);
1122
1123            PostQuitMessage (0);
1124        }
1125        break;
1126
1127		case MM_MCINOTIFY:
1128            lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
1129			break;
1130
1131    	default:
1132            /* pass all unhandled messages to DefWindowProc */
1133            lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
1134        break;
1135    }
1136
1137    /* return 1 if handled message, 0 if not */
1138    return lRet;
1139}
1140
1141
1142/*
1143=================
1144VID_NumModes
1145=================
1146*/
1147int VID_NumModes (void)
1148{
1149	return nummodes;
1150}
1151
1152
1153/*
1154=================
1155VID_GetModePtr
1156=================
1157*/
1158vmode_t *VID_GetModePtr (int modenum)
1159{
1160
1161	if ((modenum >= 0) && (modenum < nummodes))
1162		return &modelist[modenum];
1163	else
1164		return &badmode;
1165}
1166
1167
1168/*
1169=================
1170VID_GetModeDescription
1171=================
1172*/
1173char *VID_GetModeDescription (int mode)
1174{
1175	char		*pinfo;
1176	vmode_t		*pv;
1177	static char	temp[100];
1178
1179	if ((mode < 0) || (mode >= nummodes))
1180		return NULL;
1181
1182	if (!leavecurrentmode)
1183	{
1184		pv = VID_GetModePtr (mode);
1185		pinfo = pv->modedesc;
1186	}
1187	else
1188	{
1189		sprintf (temp, "Desktop resolution (%dx%d)",
1190				 modelist[MODE_FULLSCREEN_DEFAULT].width,
1191				 modelist[MODE_FULLSCREEN_DEFAULT].height);
1192		pinfo = temp;
1193	}
1194
1195	return pinfo;
1196}
1197
1198
1199// KJB: Added this to return the mode driver name in description for console
1200
1201char *VID_GetExtModeDescription (int mode)
1202{
1203	static char	pinfo[40];
1204	vmode_t		*pv;
1205
1206	if ((mode < 0) || (mode >= nummodes))
1207		return NULL;
1208
1209	pv = VID_GetModePtr (mode);
1210	if (modelist[mode].type == MS_FULLDIB)
1211	{
1212		if (!leavecurrentmode)
1213		{
1214			sprintf(pinfo,"%s fullscreen", pv->modedesc);
1215		}
1216		else
1217		{
1218			sprintf (pinfo, "Desktop resolution (%dx%d)",
1219					 modelist[MODE_FULLSCREEN_DEFAULT].width,
1220					 modelist[MODE_FULLSCREEN_DEFAULT].height);
1221		}
1222	}
1223	else
1224	{
1225		if (modestate == MS_WINDOWED)
1226			sprintf(pinfo, "%s windowed", pv->modedesc);
1227		else
1228			sprintf(pinfo, "windowed");
1229	}
1230
1231	return pinfo;
1232}
1233
1234
1235/*
1236=================
1237VID_DescribeCurrentMode_f
1238=================
1239*/
1240void VID_DescribeCurrentMode_f (void)
1241{
1242	Con_Printf ("%s\n", VID_GetExtModeDescription (vid_modenum));
1243}
1244
1245
1246/*
1247=================
1248VID_NumModes_f
1249=================
1250*/
1251void VID_NumModes_f (void)
1252{
1253
1254	if (nummodes == 1)
1255		Con_Printf ("%d video mode is available\n", nummodes);
1256	else
1257		Con_Printf ("%d video modes are available\n", nummodes);
1258}
1259
1260
1261/*
1262=================
1263VID_DescribeMode_f
1264=================
1265*/
1266void VID_DescribeMode_f (void)
1267{
1268	int		t, modenum;
1269
1270	modenum = Q_atoi (Cmd_Argv(1));
1271
1272	t = leavecurrentmode;
1273	leavecurrentmode = 0;
1274
1275	Con_Printf ("%s\n", VID_GetExtModeDescription (modenum));
1276
1277	leavecurrentmode = t;
1278}
1279
1280
1281/*
1282=================
1283VID_DescribeModes_f
1284=================
1285*/
1286void VID_DescribeModes_f (void)
1287{
1288	int			i, lnummodes, t;
1289	char		*pinfo;
1290	vmode_t		*pv;
1291
1292	lnummodes = VID_NumModes ();
1293
1294	t = leavecurrentmode;
1295	leavecurrentmode = 0;
1296
1297	for (i=1 ; i<lnummodes ; i++)
1298	{
1299		pv = VID_GetModePtr (i);
1300		pinfo = VID_GetExtModeDescription (i);
1301		Con_Printf ("%2d: %s\n", i, pinfo);
1302	}
1303
1304	leavecurrentmode = t;
1305}
1306
1307
1308void VID_InitDIB (HINSTANCE hInstance)
1309{
1310	WNDCLASS		wc;
1311	HDC				hdc;
1312	int				i;
1313
1314	/* Register the frame class */
1315    wc.style         = 0;
1316    wc.lpfnWndProc   = (WNDPROC)MainWndProc;
1317    wc.cbClsExtra    = 0;
1318    wc.cbWndExtra    = 0;
1319    wc.hInstance     = hInstance;
1320    wc.hIcon         = 0;
1321    wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
1322	wc.hbrBackground = NULL;
1323    wc.lpszMenuName  = 0;
1324    wc.lpszClassName = "WinQuake";
1325
1326    if (!RegisterClass (&wc) )
1327		Sys_Error ("Couldn't register window class");
1328
1329	modelist[0].type = MS_WINDOWED;
1330
1331	if (COM_CheckParm("-width"))
1332		modelist[0].width = Q_atoi(com_argv[COM_CheckParm("-width")+1]);
1333	else
1334		modelist[0].width = 640;
1335
1336	if (modelist[0].width < 320)
1337		modelist[0].width = 320;
1338
1339	if (COM_CheckParm("-height"))
1340		modelist[0].height= Q_atoi(com_argv[COM_CheckParm("-height")+1]);
1341	else
1342		modelist[0].height = modelist[0].width * 240/320;
1343
1344	if (modelist[0].height < 240)
1345		modelist[0].height = 240;
1346
1347	sprintf (modelist[0].modedesc, "%dx%d",
1348			 modelist[0].width, modelist[0].height);
1349
1350	modelist[0].modenum = MODE_WINDOWED;
1351	modelist[0].dib = 1;
1352	modelist[0].fullscreen = 0;
1353	modelist[0].halfscreen = 0;
1354	modelist[0].bpp = 0;
1355
1356	nummodes = 1;
1357}
1358
1359
1360/*
1361=================
1362VID_InitFullDIB
1363=================
1364*/
1365void VID_InitFullDIB (HINSTANCE hInstance)
1366{
1367	DEVMODE	devmode;
1368	int		i, modenum, cmodes, originalnummodes, existingmode, numlowresmodes;
1369	int		j, bpp, done;
1370	BOOL	stat;
1371
1372// enumerate >8 bpp modes
1373	originalnummodes = nummodes;
1374	modenum = 0;
1375
1376	do
1377	{
1378		stat = EnumDisplaySettings (NULL, modenum, &devmode);
1379
1380		if ((devmode.dmBitsPerPel >= 15) &&
1381			(devmode.dmPelsWidth <= MAXWIDTH) &&
1382			(devmode.dmPelsHeight <= MAXHEIGHT) &&
1383			(nummodes < MAX_MODE_LIST))
1384		{
1385			devmode.dmFields = DM_BITSPERPEL |
1386							   DM_PELSWIDTH |
1387							   DM_PELSHEIGHT;
1388
1389			if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
1390					DISP_CHANGE_SUCCESSFUL)
1391			{
1392				modelist[nummodes].type = MS_FULLDIB;
1393				modelist[nummodes].width = devmode.dmPelsWidth;
1394				modelist[nummodes].height = devmode.dmPelsHeight;
1395				modelist[nummodes].modenum = 0;
1396				modelist[nummodes].halfscreen = 0;
1397				modelist[nummodes].dib = 1;
1398				modelist[nummodes].fullscreen = 1;
1399				modelist[nummodes].bpp = devmode.dmBitsPerPel;
1400				sprintf (modelist[nummodes].modedesc, "%dx%dx%d",
1401						 devmode.dmPelsWidth, devmode.dmPelsHeight,
1402						 devmode.dmBitsPerPel);
1403
1404			// if the width is more than twice the height, reduce it by half because this
1405			// is probably a dual-screen monitor
1406				if (!COM_CheckParm("-noadjustaspect"))
1407				{
1408					if (modelist[nummodes].width > (modelist[nummodes].height << 1))
1409					{
1410						modelist[nummodes].width >>= 1;
1411						modelist[nummodes].halfscreen = 1;
1412						sprintf (modelist[nummodes].modedesc, "%dx%dx%d",
1413								 modelist[nummodes].width,
1414								 modelist[nummodes].height,
1415								 modelist[nummodes].bpp);
1416					}
1417				}
1418
1419				for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++)
1420				{
1421					if ((modelist[nummodes].width == modelist[i].width)   &&
1422						(modelist[nummodes].height == modelist[i].height) &&
1423						(modelist[nummodes].bpp == modelist[i].bpp))
1424					{
1425						existingmode = 1;
1426						break;
1427					}
1428				}
1429
1430				if (!existingmode)
1431				{
1432					nummodes++;
1433				}
1434			}
1435		}
1436
1437		modenum++;
1438	} while (stat);
1439
1440// see if there are any low-res modes that aren't being reported
1441	numlowresmodes = sizeof(lowresmodes) / sizeof(lowresmodes[0]);
1442	bpp = 16;
1443	done = 0;
1444
1445	do
1446	{
1447		for (j=0 ; (j<numlowresmodes) && (nummodes < MAX_MODE_LIST) ; j++)
1448		{
1449			devmode.dmBitsPerPel = bpp;
1450			devmode.dmPelsWidth = lowresmodes[j].width;
1451			devmode.dmPelsHeight = lowresmodes[j].height;
1452			devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1453
1454			if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
1455					DISP_CHANGE_SUCCESSFUL)
1456			{
1457				modelist[nummodes].type = MS_FULLDIB;
1458				modelist[nummodes].width = devmode.dmPelsWidth;
1459				modelist[nummodes].height = devmode.dmPelsHeight;
1460				modelist[nummodes].modenum = 0;
1461				modelist[nummodes].halfscreen = 0;
1462				modelist[nummodes].dib = 1;
1463				modelist[nummodes].fullscreen = 1;
1464				modelist[nummodes].bpp = devmode.dmBitsPerPel;
1465				sprintf (modelist[nummodes].modedesc, "%dx%dx%d",
1466						 devmode.dmPelsWidth, devmode.dmPelsHeight,
1467						 devmode.dmBitsPerPel);
1468
1469				for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++)
1470				{
1471					if ((modelist[nummodes].width == modelist[i].width)   &&
1472						(modelist[nummodes].height == modelist[i].height) &&
1473						(modelist[nummodes].bpp == modelist[i].bpp))
1474					{
1475						existingmode = 1;
1476						break;
1477					}
1478				}
1479
1480				if (!existingmode)
1481				{
1482					nummodes++;
1483				}
1484			}
1485		}
1486		switch (bpp)
1487		{
1488			case 16:
1489				bpp = 32;
1490				break;
1491
1492			case 32:
1493				bpp = 24;
1494				break;
1495
1496			case 24:
1497				done = 1;
1498				break;
1499		}
1500	} while (!done);
1501
1502	if (nummodes == originalnummodes)
1503		Con_SafePrintf ("No fullscreen DIB modes found\n");
1504}
1505
1506qboolean VID_Is8bit() {
1507	return is8bit;
1508}
1509
1510#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB
1511
1512void VID_Init8bitPalette()
1513{
1514	// Check for 8bit Extensions and initialize them.
1515	int i;
1516	char thePalette[256*3];
1517	char *oldPalette, *newPalette;
1518
1519	glColorTableEXT = (void *)wglGetProcAddress("glColorTableEXT");
1520    if (!glColorTableEXT || strstr(gl_extensions, "GL_EXT_shared_texture_palette") ||
1521		COM_CheckParm("-no8bit"))
1522		return;
1523
1524	Con_SafePrintf("8-bit GL extensions enabled.\n");
1525    glEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
1526	oldPalette = (char *) d_8to24table; //d_8to24table3dfx;
1527	newPalette = thePalette;
1528	for (i=0;i<256;i++) {
1529		*newPalette++ = *oldPalette++;
1530		*newPalette++ = *oldPalette++;
1531		*newPalette++ = *oldPalette++;
1532		oldPalette++;
1533	}
1534	glColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE,
1535		(void *) thePalette);
1536	is8bit = TRUE;
1537}
1538
1539static void Check_Gamma (unsigned char *pal)
1540{
1541	float	f, inf;
1542	unsigned char	palette[768];
1543	int		i;
1544
1545	if ((i = COM_CheckParm("-gamma")) == 0) {
1546		if ((gl_renderer && strstr(gl_renderer, "Voodoo")) ||
1547			(gl_vendor && strstr(gl_vendor, "3Dfx")))
1548			vid_gamma = 1;
1549		else
1550			vid_gamma = 0.7; // default to 0.7 on non-3dfx hardware
1551	} else
1552		vid_gamma = Q_atof(com_argv[i+1]);
1553
1554	for (i=0 ; i<768 ; i++)
1555	{
1556		f = pow ( (pal[i]+1)/256.0 , vid_gamma );
1557		inf = f*255 + 0.5;
1558		if (inf < 0)
1559			inf = 0;
1560		if (inf > 255)
1561			inf = 255;
1562		palette[i] = inf;
1563	}
1564
1565	memcpy (pal, palette, sizeof(palette));
1566}
1567
1568/*
1569===================
1570VID_Init
1571===================
1572*/
1573void	VID_Init (unsigned char *palette)
1574{
1575	int		i, existingmode;
1576	int		basenummodes, width, height, bpp, findbpp, done;
1577	byte	*ptmp;
1578	char	gldir[MAX_OSPATH];
1579	HDC		hdc;
1580	DEVMODE	devmode;
1581
1582	memset(&devmode, 0, sizeof(devmode));
1583
1584	Cvar_RegisterVariable (&vid_mode);
1585	Cvar_RegisterVariable (&vid_wait);
1586	Cvar_RegisterVariable (&vid_nopageflip);
1587	Cvar_RegisterVariable (&_vid_wait_override);
1588	Cvar_RegisterVariable (&_vid_default_mode);
1589	Cvar_RegisterVariable (&_vid_default_mode_win);
1590	Cvar_RegisterVariable (&vid_config_x);
1591	Cvar_RegisterVariable (&vid_config_y);
1592	Cvar_RegisterVariable (&vid_stretch_by_2);
1593	Cvar_RegisterVariable (&_windowed_mouse);
1594	Cvar_RegisterVariable (&gl_ztrick);
1595
1596	Cmd_AddCommand ("vid_nummodes", VID_NumModes_f);
1597	Cmd_AddCommand ("vid_describecurrentmode", VID_DescribeCurrentMode_f);
1598	Cmd_AddCommand ("vid_describemode", VID_DescribeMode_f);
1599	Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f);
1600
1601	hIcon = LoadIcon (global_hInstance, MAKEINTRESOURCE (IDI_ICON2));
1602
1603	InitCommonControls();
1604
1605	VID_InitDIB (global_hInstance);
1606	basenummodes = nummodes = 1;
1607
1608	VID_InitFullDIB (global_hInstance);
1609
1610	if (COM_CheckParm("-window"))
1611	{
1612		hdc = GetDC (NULL);
1613
1614		if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
1615		{
1616			Sys_Error ("Can't run in non-RGB mode");
1617		}
1618
1619		ReleaseDC (NULL, hdc);
1620
1621		windowed = true;
1622
1623		vid_default = MODE_WINDOWED;
1624	}
1625	else
1626	{
1627		if (nummodes == 1)
1628			Sys_Error ("No RGB fullscreen modes available");
1629
1630		windowed = false;
1631
1632		if (COM_CheckParm("-mode"))
1633		{
1634			vid_default = Q_atoi(com_argv[COM_CheckParm("-mode")+1]);
1635		}
1636		else
1637		{
1638			if (COM_CheckParm("-current"))
1639			{
1640				modelist[MODE_FULLSCREEN_DEFAULT].width =
1641						GetSystemMetrics (SM_CXSCREEN);
1642				modelist[MODE_FULLSCREEN_DEFAULT].height =
1643						GetSystemMetrics (SM_CYSCREEN);
1644				vid_default = MODE_FULLSCREEN_DEFAULT;
1645				leavecurrentmode = 1;
1646			}
1647			else
1648			{
1649				if (COM_CheckParm("-width"))
1650				{
1651					width = Q_atoi(com_argv[COM_CheckParm("-width")+1]);
1652				}
1653				else
1654				{
1655					width = 640;
1656				}
1657
1658				if (COM_CheckParm("-bpp"))
1659				{
1660					bpp = Q_atoi(com_argv[COM_CheckParm("-bpp")+1]);
1661					findbpp = 0;
1662				}
1663				else
1664				{
1665					bpp = 15;
1666					findbpp = 1;
1667				}
1668
1669				if (COM_CheckParm("-height"))
1670					height = Q_atoi(com_argv[COM_CheckParm("-height")+1]);
1671
1672			// if they want to force it, add the specified mode to the list
1673				if (COM_CheckParm("-force") && (nummodes < MAX_MODE_LIST))
1674				{
1675					modelist[nummodes].type = MS_FULLDIB;
1676					modelist[nummodes].width = width;
1677					modelist[nummodes].height = height;
1678					modelist[nummodes].modenum = 0;
1679					modelist[nummodes].halfscreen = 0;
1680					modelist[nummodes].dib = 1;
1681					modelist[nummodes].fullscreen = 1;
1682					modelist[nummodes].bpp = bpp;
1683					sprintf (modelist[nummodes].modedesc, "%dx%dx%d",
1684							 devmode.dmPelsWidth, devmode.dmPelsHeight,
1685							 devmode.dmBitsPerPel);
1686
1687					for (i=nummodes, existingmode = 0 ; i<nummodes ; i++)
1688					{
1689						if ((modelist[nummodes].width == modelist[i].width)   &&
1690							(modelist[nummodes].height == modelist[i].height) &&
1691							(modelist[nummodes].bpp == modelist[i].bpp))
1692						{
1693							existingmode = 1;
1694							break;
1695						}
1696					}
1697
1698					if (!existingmode)
1699					{
1700						nummodes++;
1701					}
1702				}
1703
1704				done = 0;
1705
1706				do
1707				{
1708					if (COM_CheckParm("-height"))
1709					{
1710						height = Q_atoi(com_argv[COM_CheckParm("-height")+1]);
1711
1712						for (i=1, vid_default=0 ; i<nummodes ; i++)
1713						{
1714							if ((modelist[i].width == width) &&
1715								(modelist[i].height == height) &&
1716								(modelist[i].bpp == bpp))
1717							{
1718								vid_default = i;
1719								done = 1;
1720								break;
1721							}
1722						}
1723					}
1724					else
1725					{
1726						for (i=1, vid_default=0 ; i<nummodes ; i++)
1727						{
1728							if ((modelist[i].width == width) && (modelist[i].bpp == bpp))
1729							{
1730								vid_default = i;
1731								done = 1;
1732								break;
1733							}
1734						}
1735					}
1736
1737					if (!done)
1738					{
1739						if (findbpp)
1740						{
1741							switch (bpp)
1742							{
1743							case 15:
1744								bpp = 16;
1745								break;
1746							case 16:
1747								bpp = 32;
1748								break;
1749							case 32:
1750								bpp = 24;
1751								break;
1752							case 24:
1753								done = 1;
1754								break;
1755							}
1756						}
1757						else
1758						{
1759							done = 1;
1760						}
1761					}
1762				} while (!done);
1763
1764				if (!vid_default)
1765				{
1766					Sys_Error ("Specified video mode not available");
1767				}
1768			}
1769		}
1770	}
1771
1772	vid_initialized = true;
1773
1774	if ((i = COM_CheckParm("-conwidth")) != 0)
1775		vid.conwidth = Q_atoi(com_argv[i+1]);
1776	else
1777		vid.conwidth = 640;
1778
1779	vid.conwidth &= 0xfff8; // make it a multiple of eight
1780
1781	if (vid.conwidth < 320)
1782		vid.conwidth = 320;
1783
1784	// pick a conheight that matches with correct aspect
1785	vid.conheight = vid.conwidth*3 / 4;
1786
1787	if ((i = COM_CheckParm("-conheight")) != 0)
1788		vid.conheight = Q_atoi(com_argv[i+1]);
1789	if (vid.conheight < 200)
1790		vid.conheight = 200;
1791
1792	vid.maxwarpwidth = WARP_WIDTH;
1793	vid.maxwarpheight = WARP_HEIGHT;
1794	vid.colormap = host_colormap;
1795	vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
1796
1797	DestroyWindow (hwnd_dialog);
1798
1799	Check_Gamma(palette);
1800	VID_SetPalette (palette);
1801
1802	VID_SetMode (vid_default, palette);
1803
1804    maindc = GetDC(mainwindow);
1805	bSetupPixelFormat(maindc);
1806
1807    baseRC = wglCreateContext( maindc );
1808	if (!baseRC)
1809		Sys_Error ("Could not initialize GL (wglCreateContext failed).\n\nMake sure you in are 65535 color mode, and try running -window.");
1810    if (!wglMakeCurrent( maindc, baseRC ))
1811		Sys_Error ("wglMakeCurrent failed");
1812
1813	GL_Init ();
1814
1815	sprintf (gldir, "%s/glquake", com_gamedir);
1816	Sys_mkdir (gldir);
1817
1818	vid_realmode = vid_modenum;
1819
1820	// Check for 3DFX Extensions and initialize them.
1821	VID_Init8bitPalette();
1822
1823	vid_menudrawfn = VID_MenuDraw;
1824	vid_menukeyfn = VID_MenuKey;
1825
1826	strcpy (badmode.modedesc, "Bad mode");
1827	vid_canalttab = true;
1828
1829	if (COM_CheckParm("-fullsbar"))
1830		fullsbardraw = true;
1831}
1832
1833
1834//========================================================
1835// Video menu stuff
1836//========================================================
1837
1838extern void M_Menu_Options_f (void);
1839extern void M_Print (int cx, int cy, char *str);
1840extern void M_PrintWhite (int cx, int cy, char *str);
1841extern void M_DrawCharacter (int cx, int line, int num);
1842extern void M_DrawTransPic (int x, int y, qpic_t *pic);
1843extern void M_DrawPic (int x, int y, qpic_t *pic);
1844
1845static int	vid_line, vid_wmodes;
1846
1847typedef struct
1848{
1849	int		modenum;
1850	char	*desc;
1851	int		iscur;
1852} modedesc_t;
1853
1854#define MAX_COLUMN_SIZE		9
1855#define MODE_AREA_HEIGHT	(MAX_COLUMN_SIZE + 2)
1856#define MAX_MODEDESCS		(MAX_COLUMN_SIZE*3)
1857
1858static modedesc_t	modedescs[MAX_MODEDESCS];
1859
1860/*
1861================
1862VID_MenuDraw
1863================
1864*/
1865void VID_MenuDraw (void)
1866{
1867	qpic_t		*p;
1868	char		*ptr;
1869	int			lnummodes, i, j, k, column, row, dup, dupmode;
1870	char		temp[100];
1871	vmode_t		*pv;
1872
1873	p = Draw_CachePic ("gfx/vidmodes.lmp");
1874	M_DrawPic ( (320-p->width)/2, 4, p);
1875
1876	vid_wmodes = 0;
1877	lnummodes = VID_NumModes ();
1878
1879	for (i=1 ; (i<lnummodes) && (vid_wmodes < MAX_MODEDESCS) ; i++)
1880	{
1881		ptr = VID_GetModeDescription (i);
1882		pv = VID_GetModePtr (i);
1883
1884		k = vid_wmodes;
1885
1886		modedescs[k].modenum = i;
1887		modedescs[k].desc = ptr;
1888		modedescs[k].iscur = 0;
1889
1890		if (i == vid_modenum)
1891			modedescs[k].iscur = 1;
1892
1893		vid_wmodes++;
1894
1895	}
1896
1897	if (vid_wmodes > 0)
1898	{
1899		M_Print (2*8, 36+0*8, "Fullscreen Modes (WIDTHxHEIGHTxBPP)");
1900
1901		column = 8;
1902		row = 36+2*8;
1903
1904		for (i=0 ; i<vid_wmodes ; i++)
1905		{
1906			if (modedescs[i].iscur)
1907				M_PrintWhite (column, row, modedescs[i].desc);
1908			else
1909				M_Print (column, row, modedescs[i].desc);
1910
1911			column += 13*8;
1912
1913			if ((i % VID_ROW_SIZE) == (VID_ROW_SIZE - 1))
1914			{
1915				column = 8;
1916				row += 8;
1917			}
1918		}
1919	}
1920
1921	M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*2,
1922			 "Video modes must be set from the");
1923	M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*3,
1924			 "command line with -width <width>");
1925	M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*4,
1926			 "and -bpp <bits-per-pixel>");
1927	M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*6,
1928			 "Select windowed mode with -window");
1929}
1930
1931
1932/*
1933================
1934VID_MenuKey
1935================
1936*/
1937void VID_MenuKey (int key)
1938{
1939	switch (key)
1940	{
1941	case K_ESCAPE:
1942		S_LocalSound ("misc/menu1.wav");
1943		M_Menu_Options_f ();
1944		break;
1945
1946	default:
1947		break;
1948	}
1949}
1950