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