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