vid_dos.c 15 KB

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