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 //
21 // vid_dos.c: DOS-specific video routines
22 //
23 
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <dos.h>
29 #include <dpmi.h>
30 #include <go32.h>
31 
32 #include "quakedef.h"
33 #include "d_local.h"
34 #include "dosisms.h"
35 #include "vid_dos.h"
36 
37 int			vid_modenum;
38 vmode_t		*pcurrentmode = NULL;
39 int			vid_testingmode, vid_realmode;
40 double		vid_testendtime;
41 
42 cvar_t		vid_mode = {"vid_mode","0", false};
43 cvar_t		vid_wait = {"vid_wait","0"};
44 cvar_t		vid_nopageflip = {"vid_nopageflip","0", true};
45 cvar_t		_vid_wait_override = {"_vid_wait_override", "0", true};
46 cvar_t		_vid_default_mode = {"_vid_default_mode","0", true};
47 cvar_t		_vid_default_mode_win = {"_vid_default_mode_win","1", true};
48 cvar_t		vid_config_x = {"vid_config_x","800", true};
49 cvar_t		vid_config_y = {"vid_config_y","600", true};
50 cvar_t		vid_stretch_by_2 = {"vid_stretch_by_2","1", true};
51 cvar_t		_windowed_mouse = {"_windowed_mouse","0", true};
52 cvar_t		vid_fullscreen_mode = {"vid_fullscreen_mode","3", true};
53 cvar_t		vid_windowed_mode = {"vid_windowed_mode","0", true};
54 cvar_t		block_switch = {"block_switch","0", true};
55 cvar_t		vid_window_x = {"vid_window_x", "0", true};
56 cvar_t		vid_window_y = {"vid_window_y", "0", true};
57 
58 int	d_con_indirect = 0;
59 
60 int		numvidmodes;
61 vmode_t	*pvidmodes;
62 
63 static int	firstupdate = 1;
64 
65 extern regs_t regs;
66 
67 void VID_TestMode_f (void);
68 void VID_NumModes_f (void);
69 void VID_DescribeCurrentMode_f (void);
70 void VID_DescribeMode_f (void);
71 void VID_DescribeModes_f (void);
72 
73 byte	vid_current_palette[768];	// save for mode changes
74 
75 
76 static qboolean	nomodecheck = false;
77 
78 unsigned short	d_8to16table[256];	// not used in 8 bpp mode
79 unsigned		d_8to24table[256];	// not used in 8 bpp mode
80 
81 void VID_MenuDraw (void);
82 void VID_MenuKey (int key);
83 
84 
85 /*
86 ================
87 VID_Init
88 ================
89 */
VID_Init(unsigned char * palette)90 void    VID_Init (unsigned char *palette)
91 {
92 	Cvar_RegisterVariable (&vid_mode);
93 	Cvar_RegisterVariable (&vid_wait);
94 	Cvar_RegisterVariable (&vid_nopageflip);
95 	Cvar_RegisterVariable (&_vid_wait_override);
96 	Cvar_RegisterVariable (&_vid_default_mode);
97 	Cvar_RegisterVariable (&_vid_default_mode_win);
98 	Cvar_RegisterVariable (&vid_config_x);
99 	Cvar_RegisterVariable (&vid_config_y);
100 	Cvar_RegisterVariable (&vid_stretch_by_2);
101 	Cvar_RegisterVariable (&_windowed_mouse);
102 	Cvar_RegisterVariable (&vid_fullscreen_mode);
103 	Cvar_RegisterVariable (&vid_windowed_mode);
104 	Cvar_RegisterVariable (&block_switch);
105 
106 	Cmd_AddCommand ("vid_testmode", VID_TestMode_f);
107 	Cmd_AddCommand ("vid_nummodes", VID_NumModes_f);
108 	Cmd_AddCommand ("vid_describecurrentmode", VID_DescribeCurrentMode_f);
109 	Cmd_AddCommand ("vid_describemode", VID_DescribeMode_f);
110 	Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f);
111 
112 // set up the mode list; note that later inits link in their modes ahead of
113 // earlier ones, so the standard VGA modes are always first in the list. This
114 // is important because mode 0 must always be VGA mode 0x13
115 	if (!COM_CheckParm ("-stdvid"))
116 		VID_InitExtra ();
117 	VGA_Init ();
118 
119 	vid_testingmode = 0;
120 
121 	vid_modenum = vid_mode.value;
122 
123 	VID_SetMode (vid_modenum, palette);
124 
125 	vid_realmode = vid_modenum;
126 
127 	vid_menudrawfn = VID_MenuDraw;
128 	vid_menukeyfn = VID_MenuKey;
129 }
130 
131 
132 /*
133 =================
134 VID_GetModePtr
135 =================
136 */
VID_GetModePtr(int modenum)137 vmode_t *VID_GetModePtr (int modenum)
138 {
139 	vmode_t	*pv;
140 
141 	pv = pvidmodes;
142 	if (!pv)
143 		Sys_Error ("VID_GetModePtr: empty vid mode list");
144 
145 	while (modenum--)
146 	{
147 		pv = pv->pnext;
148 		if (!pv)
149 			Sys_Error ("VID_GetModePtr: corrupt vid mode list");
150 	}
151 
152 	return pv;
153 }
154 
155 /*
156 ================
157 VID_NumModes
158 ================
159 */
VID_NumModes()160 int VID_NumModes ()
161 {
162 	return (numvidmodes);
163 }
164 
165 
166 /*
167 ================
168 VID_ModeInfo
169 ================
170 */
VID_ModeInfo(int modenum,char ** ppheader)171 char *VID_ModeInfo (int modenum, char **ppheader)
172 {
173 	static char	*badmodestr = "Bad mode number";
174 	vmode_t		*pv;
175 
176 	pv = VID_GetModePtr (modenum);
177 
178 	if (!pv)
179 	{
180 		if (ppheader)
181 			*ppheader = NULL;
182 		return badmodestr;
183 	}
184 	else
185 	{
186 		if (ppheader)
187 			*ppheader = pv->header;
188 		return pv->name;
189 	}
190 }
191 
192 
193 /*
194 ================
195 VID_SetMode
196 ================
197 */
VID_SetMode(int modenum,unsigned char * palette)198 int VID_SetMode (int modenum, unsigned char *palette)
199 {
200 	int		stat;
201 	vmode_t	*pnewmode, *poldmode;
202 
203 	if ((modenum >= numvidmodes) || (modenum < 0))
204 	{
205 		Cvar_SetValue ("vid_mode", (float)vid_modenum);
206 
207 		nomodecheck = true;
208 		Con_Printf ("No such video mode: %d\n", modenum);
209 		nomodecheck = false;
210 
211 		if (pcurrentmode == NULL)
212 		{
213 			modenum = 0;	// mode hasn't been set yet, so initialize to base
214 							//  mode since they gave us an invalid initial mode
215 		}
216 		else
217 		{
218 			return 0;
219 		}
220 	}
221 
222 	pnewmode = VID_GetModePtr (modenum);
223 
224 	if (pnewmode == pcurrentmode)
225 		return 1;	// already in the desired mode
226 
227 // initialize the new mode
228 	poldmode = pcurrentmode;
229 	pcurrentmode = pnewmode;
230 
231 	vid.width = pcurrentmode->width;
232 	vid.height = pcurrentmode->height;
233 	vid.aspect = pcurrentmode->aspect;
234 	vid.rowbytes = pcurrentmode->rowbytes;
235 
236 	stat = (*pcurrentmode->setmode) (&vid, pcurrentmode);
237 
238 	if (stat < 1)
239 	{
240 		if (stat == 0)
241 		{
242 		// real, hard failure that requires resetting the mode
243 			if (!VID_SetMode (vid_modenum, palette))	// restore prior mode
244 				Sys_Error ("VID_SetMode: Unable to set any mode, probably "
245 						   "because there's not enough memory available");
246 			Con_Printf ("Failed to set mode %d\n", modenum);
247 			return 0;
248 		}
249 		else if (stat == -1)
250 		{
251 		// not enough memory; just put things back the way they were
252 			pcurrentmode = poldmode;
253 			vid.width = pcurrentmode->width;
254 			vid.height = pcurrentmode->height;
255 			vid.aspect = pcurrentmode->aspect;
256 			vid.rowbytes = pcurrentmode->rowbytes;
257 			return 0;
258 		}
259 		else
260 		{
261 			Sys_Error ("VID_SetMode: invalid setmode return code %d");
262 		}
263 	}
264 
265 	(*pcurrentmode->setpalette) (&vid, pcurrentmode, palette);
266 
267 	vid_modenum = modenum;
268 	Cvar_SetValue ("vid_mode", (float)vid_modenum);
269 
270 	nomodecheck = true;
271 	Con_Printf ("%s\n", VID_ModeInfo (vid_modenum, NULL));
272 	nomodecheck = false;
273 
274 	vid.recalc_refdef = 1;
275 
276 	return 1;
277 }
278 
279 
280 /*
281 ================
282 VID_SetPalette
283 ================
284 */
VID_SetPalette(unsigned char * palette)285 void    VID_SetPalette (unsigned char *palette)
286 {
287 	if (palette != vid_current_palette)
288 		Q_memcpy(vid_current_palette, palette, 768);
289 	(*pcurrentmode->setpalette)(&vid, pcurrentmode, vid_current_palette);
290 }
291 
292 
293 /*
294 ================
295 VID_ShiftPalette
296 ================
297 */
VID_ShiftPalette(unsigned char * palette)298 void    VID_ShiftPalette (unsigned char *palette)
299 {
300 
301 	VID_SetPalette (palette);
302 }
303 
304 
305 /*
306 ================
307 VID_Shutdown
308 ================
309 */
VID_Shutdown(void)310 void VID_Shutdown (void)
311 {
312 
313 	regs.h.ah = 0;
314 	regs.h.al = 0x3;
315 	dos_int86(0x10);
316 
317 	vid_testingmode = 0;
318 }
319 
320 
321 /*
322 ================
323 VID_Update
324 ================
325 */
VID_Update(vrect_t * rects)326 void    VID_Update (vrect_t *rects)
327 {
328 	if (firstupdate && _vid_default_mode.value)
329 	{
330 		if(_vid_default_mode.value >= numvidmodes)
331 			Cvar_SetValue ("_vid_default_mode", 0);
332 
333 		firstupdate = 0;
334 		Cvar_SetValue ("vid_mode", _vid_default_mode.value);
335 	}
336 
337 	(*pcurrentmode->swapbuffers)(&vid, pcurrentmode, rects);
338 
339 	if (!nomodecheck)
340 	{
341 		if (vid_testingmode)
342 		{
343 			if (realtime >= vid_testendtime)
344 			{
345 				VID_SetMode (vid_realmode, vid_current_palette);
346 				vid_testingmode = 0;
347 			}
348 		}
349 		else
350 		{
351 			if (vid_mode.value != vid_realmode)
352 			{
353 				VID_SetMode ((int)vid_mode.value, vid_current_palette);
354 				Cvar_SetValue ("vid_mode", (float)vid_modenum);
355 									// so if mode set fails, we don't keep on
356 									//  trying to set that mode
357 				vid_realmode = vid_modenum;
358 			}
359 		}
360 	}
361 }
362 
363 
364 /*
365 =================
366 VID_NumModes_f
367 =================
368 */
VID_NumModes_f(void)369 void VID_NumModes_f (void)
370 {
371 	int		nummodes;
372 
373 	nummodes = VID_NumModes ();
374 	if (nummodes == 1)
375 		Con_Printf ("%d video mode is available\n", VID_NumModes ());
376 	else
377 		Con_Printf ("%d video modes are available\n", VID_NumModes ());
378 }
379 
380 
381 /*
382 =================
383 VID_DescribeCurrentMode_f
384 =================
385 */
VID_DescribeCurrentMode_f(void)386 void VID_DescribeCurrentMode_f (void)
387 {
388 	Con_Printf ("%s\n", VID_ModeInfo (vid_modenum, NULL));
389 }
390 
391 
392 /*
393 =================
394 VID_DescribeMode_f
395 =================
396 */
VID_DescribeMode_f(void)397 void VID_DescribeMode_f (void)
398 {
399 	int		modenum;
400 
401 	modenum = Q_atoi (Cmd_Argv(1));
402 
403 	Con_Printf ("%s\n", VID_ModeInfo (modenum, NULL));
404 }
405 
406 
407 /*
408 =================
409 VID_DescribeModes_f
410 =================
411 */
VID_DescribeModes_f(void)412 void VID_DescribeModes_f (void)
413 {
414 	int			i, nummodes;
415 	char		*pinfo, *pheader;
416 	vmode_t		*pv;
417 	qboolean	na;
418 
419 	na = false;
420 
421 	nummodes = VID_NumModes ();
422 	for (i=0 ; i<nummodes ; i++)
423 	{
424 		pv = VID_GetModePtr (i);
425 		pinfo = VID_ModeInfo (i, &pheader);
426 		if (pheader)
427 			Con_Printf ("\n%s\n", pheader);
428 
429 		if (VGA_CheckAdequateMem (pv->width, pv->height, pv->rowbytes,
430 			(pv->numpages == 1) || vid_nopageflip.value))
431 		{
432 			Con_Printf ("%2d: %s\n", i, pinfo);
433 		}
434 		else
435 		{
436 			Con_Printf ("**: %s\n", pinfo);
437 			na = true;
438 		}
439 	}
440 
441 	if (na)
442 	{
443 		Con_Printf ("\n[**: not enough system RAM for mode]\n");
444 	}
445 }
446 
447 
448 /*
449 =================
450 VID_GetModeDescription
451 =================
452 */
VID_GetModeDescription(int mode)453 char *VID_GetModeDescription (int mode)
454 {
455 	char		*pinfo, *pheader;
456 	vmode_t		*pv;
457 
458 	pv = VID_GetModePtr (mode);
459 	pinfo = VID_ModeInfo (mode, &pheader);
460 
461 	if (VGA_CheckAdequateMem (pv->width, pv->height, pv->rowbytes,
462 		(pv->numpages == 1) || vid_nopageflip.value))
463 	{
464 		return pinfo;
465 	}
466 	else
467 	{
468 		return NULL;
469 	}
470 }
471 
472 
473 /*
474 =================
475 VID_TestMode_f
476 =================
477 */
VID_TestMode_f(void)478 void VID_TestMode_f (void)
479 {
480 	int		modenum;
481 	double	testduration;
482 
483 	if (!vid_testingmode)
484 	{
485 		modenum = Q_atoi (Cmd_Argv(1));
486 
487 		if (VID_SetMode (modenum, vid_current_palette))
488 		{
489 			vid_testingmode = 1;
490 			testduration = Q_atof (Cmd_Argv(2));
491 			if (testduration == 0)
492 				testduration = 5.0;
493 			vid_testendtime = realtime + testduration;
494 		}
495 	}
496 }
497 
498 
499 /*
500 ================
501 D_BeginDirectRect
502 ================
503 */
D_BeginDirectRect(int x,int y,byte * pbitmap,int width,int height)504 void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
505 {
506 
507 	if (!vid.direct || !pcurrentmode)
508 		return;
509 
510 	if ((width > 24) || (height > 24) || (width < 1) || (height < 1))
511 		return;
512 
513 	if (width & 0x03)
514 		return;
515 
516 	(*pcurrentmode->begindirectrect) (&vid, pcurrentmode, x, y, pbitmap, width,
517 									  height);
518 }
519 
520 
521 /*
522 ================
523 D_EndDirectRect
524 ================
525 */
D_EndDirectRect(int x,int y,int width,int height)526 void D_EndDirectRect (int x, int y, int width, int height)
527 {
528 
529 	if (!vid.direct || !pcurrentmode)
530 		return;
531 
532 	if ((width > 24) || (height > 24) || (width < 1) || (height < 1))
533 		return;
534 
535 	if ((width & 0x03) || (height & 0x03))
536 		return;
537 
538 	(*pcurrentmode->enddirectrect) (&vid, pcurrentmode, x, y, width, height);
539 }
540 
541 
542 //===========================================================================
543 
544 extern void M_Menu_Options_f (void);
545 extern void M_Print (int cx, int cy, char *str);
546 extern void M_PrintWhite (int cx, int cy, char *str);
547 extern void M_DrawCharacter (int cx, int line, int num);
548 extern void M_DrawTransPic (int x, int y, qpic_t *pic);
549 extern void M_DrawPic (int x, int y, qpic_t *pic);
550 
551 static int	vid_line, vid_wmodes, vid_column_size;
552 
553 typedef struct
554 {
555 	int		modenum;
556 	char	*desc;
557 	int		iscur;
558 } modedesc_t;
559 
560 #define MAX_COLUMN_SIZE	11
561 
562 #define MAX_MODEDESCS	(MAX_COLUMN_SIZE*3)
563 
564 static modedesc_t	modedescs[MAX_MODEDESCS];
565 
566 /*
567 ================
568 VID_MenuDraw
569 ================
570 */
VID_MenuDraw(void)571 void VID_MenuDraw (void)
572 {
573 	qpic_t		*p;
574 	char		*ptr;
575 	int			nummodes, i, j, column, row, dup;
576 	char		temp[100];
577 
578 	vid_wmodes = 0;
579 	nummodes = VID_NumModes ();
580 
581 	p = Draw_CachePic ("gfx/vidmodes.lmp");
582 	M_DrawPic ( (320-p->width)/2, 4, p);
583 
584 	for (i=0 ; i<nummodes ; i++)
585 	{
586 		if (vid_wmodes < MAX_MODEDESCS)
587 		{
588 			if (i != 1)
589 			{
590 				ptr = VID_GetModeDescription (i);
591 
592 				if (ptr)
593 				{
594 					dup = 0;
595 
596 					for (j=0 ; j<vid_wmodes ; j++)
597 					{
598 						if (!strcmp (modedescs[j].desc, ptr))
599 						{
600 							if (modedescs[j].modenum != 0)
601 							{
602 								modedescs[j].modenum = i;
603 								dup = 1;
604 
605 								if (i == vid_modenum)
606 									modedescs[j].iscur = 1;
607 							}
608 							else
609 							{
610 								dup = 1;
611 							}
612 
613 							break;
614 						}
615 					}
616 
617 					if (!dup)
618 					{
619 						modedescs[vid_wmodes].modenum = i;
620 						modedescs[vid_wmodes].desc = ptr;
621 						modedescs[vid_wmodes].iscur = 0;
622 
623 						if (i == vid_modenum)
624 							modedescs[vid_wmodes].iscur = 1;
625 
626 						vid_wmodes++;
627 					}
628 				}
629 			}
630 		}
631 	}
632 
633 	vid_column_size = (vid_wmodes + 2) / 3;
634 
635 	column = 16;
636 	row = 36;
637 
638 	for (i=0 ; i<vid_wmodes ; i++)
639 	{
640 		if (modedescs[i].iscur)
641 			M_PrintWhite (column, row, modedescs[i].desc);
642 		else
643 			M_Print (column, row, modedescs[i].desc);
644 
645 		row += 8;
646 
647 		if ((i % vid_column_size) == (vid_column_size - 1))
648 		{
649 			column += 13*8;
650 			row = 36;
651 		}
652 	}
653 
654 // line cursor
655 	if (vid_testingmode)
656 	{
657 		sprintf (temp, "TESTING %s",
658 				modedescs[vid_line].desc);
659 		M_Print (13*8, 36 + MAX_COLUMN_SIZE * 8 + 8*4, temp);
660 		M_Print (9*8, 36 + MAX_COLUMN_SIZE * 8 + 8*6,
661 				"Please wait 5 seconds...");
662 	}
663 	else
664 	{
665 		M_Print (9*8, 36 + MAX_COLUMN_SIZE * 8 + 8,
666 				"Press Enter to set mode");
667 		M_Print (6*8, 36 + MAX_COLUMN_SIZE * 8 + 8*3,
668 				"T to test mode for 5 seconds");
669 		ptr = VID_GetModeDescription (vid_modenum);
670 		sprintf (temp, "D to make %s the default", ptr);
671 		M_Print (6*8, 36 + MAX_COLUMN_SIZE * 8 + 8*5, temp);
672 		ptr = VID_GetModeDescription ((int)_vid_default_mode.value);
673 
674 		if (ptr)
675 		{
676 			sprintf (temp, "Current default is %s", ptr);
677 			M_Print (7*8, 36 + MAX_COLUMN_SIZE * 8 + 8*6, temp);
678 		}
679 
680 		M_Print (15*8, 36 + MAX_COLUMN_SIZE * 8 + 8*8,
681 				"Esc to exit");
682 
683 		row = 36 + (vid_line % vid_column_size) * 8;
684 		column = 8 + (vid_line / vid_column_size) * 13*8;
685 
686 		M_DrawCharacter (column, row, 12+((int)(realtime*4)&1));
687 	}
688 }
689 
690 
691 /*
692 ================
693 VID_MenuKey
694 ================
695 */
VID_MenuKey(int key)696 void VID_MenuKey (int key)
697 {
698 	if (vid_testingmode)
699 		return;
700 
701 	switch (key)
702 	{
703 	case K_ESCAPE:
704 		S_LocalSound ("misc/menu1.wav");
705 		M_Menu_Options_f ();
706 		break;
707 
708 	case K_UPARROW:
709 		S_LocalSound ("misc/menu1.wav");
710 		vid_line--;
711 
712 		if (vid_line < 0)
713 			vid_line = vid_wmodes - 1;
714 		break;
715 
716 	case K_DOWNARROW:
717 		S_LocalSound ("misc/menu1.wav");
718 		vid_line++;
719 
720 		if (vid_line >= vid_wmodes)
721 			vid_line = 0;
722 		break;
723 
724 	case K_LEFTARROW:
725 		S_LocalSound ("misc/menu1.wav");
726 		vid_line -= vid_column_size;
727 
728 		if (vid_line < 0)
729 		{
730 			vid_line += ((vid_wmodes + (vid_column_size - 1)) /
731 					vid_column_size) * vid_column_size;
732 
733 			while (vid_line >= vid_wmodes)
734 				vid_line -= vid_column_size;
735 		}
736 		break;
737 
738 	case K_RIGHTARROW:
739 		S_LocalSound ("misc/menu1.wav");
740 		vid_line += vid_column_size;
741 
742 		if (vid_line >= vid_wmodes)
743 		{
744 			vid_line -= ((vid_wmodes + (vid_column_size - 1)) /
745 					vid_column_size) * vid_column_size;
746 
747 			while (vid_line < 0)
748 				vid_line += vid_column_size;
749 		}
750 		break;
751 
752 	case K_ENTER:
753 		S_LocalSound ("misc/menu1.wav");
754 		VID_SetMode (modedescs[vid_line].modenum, vid_current_palette);
755 		break;
756 
757 	case 'T':
758 	case 't':
759 		S_LocalSound ("misc/menu1.wav");
760 		if (VID_SetMode (modedescs[vid_line].modenum, vid_current_palette))
761 		{
762 			vid_testingmode = 1;
763 			vid_testendtime = realtime + 5.0;
764 		}
765 		break;
766 
767 	case 'D':
768 	case 'd':
769 		S_LocalSound ("misc/menu1.wav");
770 		firstupdate = 0;
771 		Cvar_SetValue ("_vid_default_mode", vid_modenum);
772 		break;
773 
774 	default:
775 		break;
776 	}
777 }
778 
779