home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / glquake_src / vid_amiga.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-07  |  16.9 KB  |  716 lines

  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. /*
  22. ** vid_amiga.c
  23. **
  24. ** Amiga Video Drivers
  25. **
  26. ** AGA, CGX and ChunkyPPC
  27. **
  28. ** Written by Frank Wille <frank@phoenix.owl.de>
  29. **     and Steffen Häuser <magicsn@birdland.es.bawue.de>
  30. **
  31. ** FIXME: Support for DirectRect is missing
  32. **
  33. */
  34.  
  35. #define  CALC_SURFCACHE
  36.  
  37. #include <exec/libraries.h>
  38. #include <exec/memory.h>
  39. #include <intuition/screens.h>
  40. #include <proto/exec.h>
  41. #ifdef __PPC__
  42. #ifdef WOS
  43. #include <clib/powerpc_protos.h>
  44. #else
  45. #include <powerup/gcclib/powerup_protos.h>
  46. #endif
  47. #endif
  48.  
  49. #include "quakedef.h"
  50. #include "d_local.h"
  51. #include "vid_amiga.h"
  52.  
  53.  
  54. extern byte *r_warpbuffer;
  55.  
  56. #define AGAC2P 0
  57. #define CYBERGFX 1
  58. #define CHUNKYPPC 2
  59. static int gfxmode = CYBERGFX;  /* one of the constants above */
  60.  
  61. /* Library bases used by the video drivers */
  62. struct Library *GfxBase=NULL;
  63. struct Library *CyberGfxBase=NULL;
  64. struct Library *P96Base=NULL;
  65. struct Library *RtgBase=NULL;
  66. struct Library *ChunkyPPCBase=NULL;
  67. struct Library *IntuitionBase=NULL;
  68. struct Library *AslBase=NULL;
  69.  
  70. viddef_t vid;                    /* global video state */
  71. byte *vid_buffer = NULL;
  72. short *zbuffer = NULL;
  73. static int vid_buf_offs = 0;
  74. int config_notify=0;
  75. int shutdown_keyboard=0;
  76. struct Screen *QuakeScreen = NULL;  /* will be assigned by the video driver */
  77.  
  78. #ifndef CALC_SURFCACHE
  79. #define SURFCACHESIZE_SMALL     256*1024
  80. #define SURFCACHESIZE_MEDIUM    512*1024
  81. #define SURFCACHESIZE_LARGE     1024*1024
  82. static byte surfcache[SURFCACHESIZE_LARGE];
  83. #else
  84. static byte* surfcache;
  85. static int surfcachesize;
  86. #endif
  87.  
  88. unsigned short d_8to16table[256];
  89. unsigned d_8to24table[256];
  90.  
  91. unsigned char rawkeyconv[] = {
  92.   '`','1','2','3','4','5','6','7','8','9','0','-','=','\\',0,'0',
  93.   'q','w','e','r','t','y','u','i','o','p','[',']',0,K_END,K_DOWNARROW,K_PGDN,
  94.   'a','s','d','f','g','h','j','k','l',';','\'',K_F12,0,K_LEFTARROW,0,K_RIGHTARROW,
  95.   K_F11,'z','x','c','v','b','n','m',',','.','/',0,0,K_HOME,K_UPARROW,K_PGUP,
  96.   K_SPACE,K_BACKSPACE,K_TAB,K_ENTER,K_ENTER,K_ESCAPE,K_DEL,0,
  97.   0,0,'-',0,K_UPARROW,K_DOWNARROW,K_RIGHTARROW,K_LEFTARROW,
  98.   K_F1,K_F2,K_F3,K_F4,K_F5,K_F6,K_F7,K_F8,K_F9,K_F10,'(',')','/','*','+',K_PAUSE,
  99.   K_SHIFT,K_SHIFT,0,K_CTRL,K_ALT,K_ALT,0,0,
  100.   K_MOUSE1,K_MOUSE2,K_MOUSE3
  101. };
  102.  
  103.  
  104. void VID_MenuDraw (void);
  105. void VID_MenuKey (int);
  106. void M_Menu_Options_f(void);
  107.  
  108. byte vid_current_palette[768];
  109.  
  110.  
  111.  
  112. void VID_SetPalette (unsigned char *palette)
  113. {
  114.   if (palette!=vid_current_palette) Q_memcpy(vid_current_palette,palette,768);
  115.  
  116.   switch (gfxmode) {
  117.     case AGAC2P:
  118.       VID_SetPalette_AGA(palette);
  119.       break;
  120.     case CYBERGFX:
  121.       VID_SetPalette_CGFX(palette);
  122.       break;
  123.     case CHUNKYPPC:
  124.       VID_SetPalette_ChunkyPPC(palette);
  125.       break;
  126.   }
  127. }
  128.  
  129.  
  130. void VID_ShiftPalette (unsigned char *palette)
  131. {
  132.   VID_SetPalette(palette);
  133. }
  134.  
  135. int vid_modenum;
  136. int modearray_x[11]={320,320,320,400,480,512,640,640,800,1024,1280};
  137. int modearray_y[11]={200,240,400,300,384,384,400,480,600,768,1024};
  138.  
  139. void VID_MenuDraw(void);
  140. void VID_MenuKey(int key);
  141.  
  142. cvar_t vid_mode={"vid_mode","1",false};
  143. cvar_t _vid_default_mode={"_vid_default_mode","1",true};
  144.  
  145. int firstopen=1;
  146.  
  147. void VID_Init (unsigned char *palette)
  148. {
  149.   char *module = "VID_Init: ";
  150.   int i;
  151.  
  152.   if (!(IntuitionBase = OpenLibrary("intuition.library",36)))
  153.           Sys_Error("%sCan't open intuition.library V36",module);
  154.  
  155.   if (firstopen)
  156.   {
  157.    Cvar_RegisterVariable(&vid_mode);
  158.    Cvar_RegisterVariable(&_vid_default_mode);
  159.    vid_modenum=_vid_default_mode.value;
  160.    Cvar_SetValue("vid_mode",vid_modenum);
  161.    firstopen=0;
  162.   }
  163.  
  164.   gfxmode=-1;
  165.  
  166.   if (i = COM_CheckParm("-cppc"))
  167.     gfxmode = CHUNKYPPC;
  168.   if (i = COM_CheckParm("-cgfx"))
  169.     gfxmode = CYBERGFX;
  170.   if (i = COM_CheckParm("-aga"))
  171.     gfxmode = AGAC2P;
  172.  
  173.   if (gfxmode==-1)
  174.   {
  175.     char strMode[255];
  176.     if (0<GetVar("env:Quake1/gfxmode",strMode,255,0))
  177.     {
  178.       if (!stricmp(strMode,"chunkyppc")) gfxmode=CHUNKYPPC;
  179.       else if (!stricmp(strMode,"cybergfx")) gfxmode=CYBERGFX;
  180.       else if (!stricmp(strMode,"agac2p")) gfxmode=AGAC2P;
  181.       else gfxmode=CHUNKYPPC;
  182.     }
  183.     else 
  184.     {
  185. #ifdef WOS
  186.       struct Library *LibBase=OpenLibrary("chunkyppc.library",13);
  187.       if (LibBase)
  188.       {
  189.         gfxmode=CHUNKYPPC;
  190.         CloseLibrary(LibBase);
  191.         LibBase=0;
  192.       }
  193.       else gfxmode=CYBERGFX;  
  194. #else
  195.       gfxmode=CHUNKYPPC;
  196. #endif
  197.     }
  198.   }
  199.  
  200.   switch (gfxmode) {
  201.     case AGAC2P:
  202.       VID_Init_AGA(palette);
  203.       break;
  204.     case CYBERGFX:
  205.       VID_Init_CGFX(palette);
  206.       break;
  207.     case CHUNKYPPC:
  208.       VID_Init_ChunkyPPC(palette);
  209.       break;
  210.   }
  211.  
  212.   vid.colormap = host_colormap;
  213.   vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
  214.  
  215. #ifdef __PPC__
  216. #ifdef WOS
  217.   if (!(vid_buffer = (byte *)AllocVecPPC(vid.width * vid.height,
  218.                                          MEMF_FAST|MEMF_PUBLIC,0)))
  219.     Sys_Error("%sNot enough memory for video buffer",module);
  220.   if (!(zbuffer = (short *)AllocVecPPC(vid.width * vid.height * 2,
  221.                                        MEMF_FAST|MEMF_PUBLIC,0)))
  222.     Sys_Error("%sNot enough memory for z-buffer",module);
  223.   if (!(r_warpbuffer = (byte *)AllocVecPPC(vid.width * vid.height,
  224.                                            MEMF_FAST|MEMF_PUBLIC,0)))
  225.     Sys_Error("%sNot enough memory for warp buffer",module);
  226.  
  227. #else /* PowerUp */
  228.   if (!(vid_buffer = (byte *)PPCAllocVec(vid.width * vid.height,
  229.                                          MEMF_FAST|MEMF_PUBLIC)))
  230.     Sys_Error("%sNot enough memory for video buffer",module);
  231.   if (!(zbuffer = (short *)PPCAllocVec(vid.width * vid.height * 2,
  232.                                        MEMF_FAST|MEMF_PUBLIC)))
  233.     Sys_Error("%sNot enough memory for z-buffer",module);
  234.   if (!(r_warpbuffer = (byte *)PPCAllocVec(vid.width * vid.height,
  235.                                            MEMF_FAST|MEMF_PUBLIC)))
  236.     Sys_Error("%sNot enough memory for warp buffer",module);
  237. #endif
  238.  
  239. #else /* M68k */
  240.   if (!(vid_buffer = (byte *)AllocMem(vid.width * vid.height + 8,
  241.                                       MEMF_FAST|MEMF_PUBLIC)))
  242.     Sys_Error("%sNot enough memory for video buffer",module);
  243.   if ((ULONG)vid_buffer & 8) {   /* 16-byte aligment */
  244.     vid_buffer += 8;
  245.     vid_buf_offs = 8;
  246.   }
  247.   if (!(zbuffer = (short *)AllocMem(vid.width * vid.height * 2,
  248.                                     MEMF_FAST|MEMF_PUBLIC)))
  249.     Sys_Error("%sNot enough memory for z-buffer",module);
  250.   if (!(r_warpbuffer = (byte *)AllocMem(vid.width * vid.height,
  251.                                         MEMF_FAST|MEMF_PUBLIC)))
  252.     Sys_Error("%sNot enough memory for warp buffer",module);
  253. #endif
  254.  
  255.   vid.conbuffer = vid.buffer = vid_buffer;
  256.   d_pzbuffer = zbuffer;
  257.   vid.maxwarpwidth = vid.rowbytes;
  258.   vid.maxwarpheight = vid.height;
  259.  
  260. #ifndef CALC_SURFCACHE
  261.   if ((vid.width*vid.height) < 65000)
  262.     D_InitCaches (surfcache, SURFCACHESIZE_SMALL);
  263.   else if ((vid.width*vid.height) < 200000)
  264.     D_InitCaches (surfcache, SURFCACHESIZE_MEDIUM);
  265.   else
  266.     D_InitCaches (surfcache, SURFCACHESIZE_LARGE);
  267.  
  268. #else
  269.   surfcachesize = D_SurfaceCacheForRes(vid.width,vid.height);
  270.  
  271. #ifdef __PPC__
  272. #ifdef WOS
  273.   if (!(surfcache = (byte *)AllocVecPPC(surfcachesize,MEMF_FAST,0)))
  274.     Sys_Error("%sNot enough memory for surface cache",module);
  275. #else /* PowerUp */
  276.   if (!(surfcache = (byte *)PPCAllocVec(surfcachesize,MEMF_FAST)))
  277.     Sys_Error("%sNot enough memory for surface cache",module);
  278. #endif
  279. #else /* M68k */
  280.   if (!(surfcache = (byte *)AllocMem(surfcachesize,MEMF_FAST)))
  281.     Sys_Error("%sNot enough memory for surface cache",module);
  282. #endif
  283.   D_InitCaches (surfcache, surfcachesize);
  284. #endif
  285.   if (gfxmode!=AGAC2P)
  286.   {
  287.     vid_menudrawfn=VID_MenuDraw;
  288.     vid_menukeyfn=VID_MenuKey;
  289.   }
  290.   else
  291.   {
  292.     vid_menudrawfn=0;
  293.     vid_menukeyfn=0;
  294.   }
  295. }
  296.  
  297.  
  298. void VID_Shutdown (void)
  299. {
  300.   D_FlushCaches();
  301. #ifdef __PPC__
  302. #ifdef WOS
  303. #ifdef CALC_SURFCACHE
  304.   if (surfcache)
  305.     FreeVecPPC(surfcache);
  306. #endif
  307.   if (r_warpbuffer)
  308.     FreeVecPPC(r_warpbuffer);
  309.   if (zbuffer)
  310.     FreeVecPPC(zbuffer);
  311.   if (vid_buffer)
  312.     FreeVecPPC(vid_buffer);
  313.  
  314. #else /* PowerUp */
  315. #ifdef CALC_SURFCACHE
  316.   if (surfcache)
  317.     PPCFreeVec(surfcache);
  318. #endif
  319.   if (r_warpbuffer)
  320.     PPCFreeVec(r_warpbuffer);
  321.   if (zbuffer)
  322.     PPCFreeVec(zbuffer);
  323.   if (vid_buffer)
  324.     PPCFreeVec(vid_buffer);
  325. #endif
  326.  
  327. #else /* M68k */
  328. #ifndef CALC_SURFCACHE
  329.   if (surfcache)
  330.     FreeMem(surfcache,surfcachesize);
  331. #endif
  332.   if (r_warpbuffer)
  333.     FreeMem(r_warpbuffer,vid.width * vid.height);
  334.   if (zbuffer)
  335.     FreeMem(zbuffer,vid.width * vid.height * 2);
  336.   if (vid_buffer)
  337.     FreeMem(vid_buffer-vid_buf_offs,vid.width*vid.height + 8);
  338. #endif
  339.  
  340.   switch (gfxmode) {
  341.     case AGAC2P:
  342.       VID_Shutdown_AGA();
  343.       break;
  344.     case CYBERGFX:
  345.       VID_Shutdown_CGFX();
  346.       break;
  347.     case CHUNKYPPC:
  348.       VID_Shutdown_ChunkyPPC();
  349.       break;
  350.   }
  351.   
  352.   if (IntuitionBase)
  353.     CloseLibrary(IntuitionBase);
  354. }
  355.  
  356. void VID_Update (vrect_t *rects)
  357. {
  358.   if (config_notify)
  359.   {
  360.     D_FlushCaches();
  361.     vid.recalc_refdef=1;
  362. #ifdef WOS
  363.     if (vid_buffer) FreeVecPPC(vid_buffer);
  364.     vid_buffer=0;
  365.     if (zbuffer) FreeVecPPC(zbuffer);
  366.     zbuffer=0;
  367.     if (r_warpbuffer) FreeVecPPC(r_warpbuffer);
  368.     d_viewbuffer=r_warpbuffer;
  369.     r_warpbuffer=0;
  370. #ifdef CALC_SURFCACHE
  371.     if (surfcache) FreeVecPPC(surfcache);
  372.     surfcache=0;
  373. #endif
  374. #else
  375. #ifdef __PPC__
  376.     if (vid_buffer) PPCFreeVec(vid_buffer);
  377.     vid_buffer=0;
  378.     if (zbuffer) PPCFreeVec(zbuffer);
  379.     zbuffer=0;
  380.     if (r_warpbuffer) PPCFreeVec(r_warpbuffer);
  381.     d_viewbuffer=r_warpbuffer;
  382.     r_warpbuffer=0;
  383. #ifdef CALC_SURFCACHE
  384.     if (surfcache) PPCFreeVec(surfcache);
  385.     surfcache=0;
  386. #endif
  387. #else
  388.     if (vid_buffer) FreeMem(vid_buffer-vid_buf_offs,vid.width*vid.height + 8);
  389.     vid_buffer=0;
  390.     if (zbuffer) FreeMem(zbuffer,vid.width * vid.height * 2);
  391.     zbuffer=0;
  392.     if (r_warpbuffer) FreeMem(r_warpbuffer,vid.width * vid.height);
  393.     d_viewbuffer=r_warpbuffer;
  394.     r_warpbuffer=0;
  395. #ifdef CALC_SURFCACHE
  396.     if (surfcache) FreeMem(surfcache,surfcachesize);
  397.     surfcache=0;
  398. #endif
  399. #endif
  400. #endif
  401.     if (gfxmode==CYBERGFX) VID_Shutdown_CGFX();
  402.     VID_Init(vid_current_palette);
  403.     shutdown_keyboard=1;
  404.     config_notify=0;
  405.     Con_CheckResize();
  406.     Con_Clear_f();
  407.     return;
  408.   }
  409.  
  410.   switch (gfxmode) {
  411.     case AGAC2P:
  412.       VID_Update_AGA(rects);
  413.       break;
  414.     case CYBERGFX:
  415.       VID_Update_CGFX(rects);
  416.       break;
  417.     case CHUNKYPPC:
  418.       VID_Update_ChunkyPPC(rects);
  419.       break;
  420.   }
  421. }
  422.  
  423.  
  424. void Sys_SendKeyEvents (void)
  425. {
  426.   switch (gfxmode) {
  427.     case AGAC2P:
  428.       Sys_SendKeyEvents_AGA();
  429.       break;
  430.     case CYBERGFX:
  431.       Sys_SendKeyEvents_CGFX();
  432.       break;
  433.     case CHUNKYPPC:
  434.       Sys_SendKeyEvents_ChunkyPPC();
  435.       break;
  436.   }
  437. }
  438.  
  439.  
  440. /*
  441. ================
  442. D_BeginDirectRect
  443. ================
  444. */
  445. void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
  446. {
  447. }
  448.  
  449.  
  450. /*
  451. ================
  452. D_EndDirectRect
  453. ================
  454. */
  455. void D_EndDirectRect (int x, int y, int width, int height)
  456. {
  457. }
  458.  
  459.  
  460. int numvidmodes=11;
  461. static int vid_wmodes,vid_line;
  462. int vid_column_size;
  463.  
  464. typedef struct
  465. {
  466.   int     modenum;
  467.   char    *desc;
  468.   int     iscur;
  469. } modedesc_t;
  470.  
  471. #define MAX_COLUMN_SIZE 11
  472. #define MAX_MODEDESCS   33
  473. static modedesc_t   modedescs[33];
  474.  
  475. typedef struct vmode_s {
  476.   struct vmode_s *pnext;
  477.   char           *name;
  478.   char           *header;
  479.   unsigned       width;
  480.   unsigned       height;
  481. } vmode_t;
  482.  
  483.  
  484. vmode_t vmode10={0,"1280*1024","HiRes V",1280,1024};
  485. vmode_t vmode9={&vmode10,"1024*768","HiRes IV",1024,768};
  486. vmode_t vmode8={&vmode9,"800*600","HiRes III",800,600};
  487. vmode_t vmode7={&vmode8,"640*480","HiRes II",640,480};
  488. vmode_t vmode6={&vmode7,"640*400","HiRes I",640,400};
  489. vmode_t vmode5={&vmode6,"512*384","MedRes III",512,384};
  490. vmode_t vmode4={&vmode5,"480*384","MedRes II",480,384};
  491. vmode_t vmode3={&vmode4,"400*300","MedRes I",400,300};
  492. vmode_t vmode2={&vmode3,"320*400","LowRes III",320,400};
  493. vmode_t vmode1={&vmode2,"320*240","LowRes II",320,240};
  494. vmode_t vmode0={&vmode1,"320*200","LowRes I",320,200};
  495. vmode_t *pvidmodes=&vmode0;
  496.  
  497. int VID_NumModes ()
  498. {
  499.   return (numvidmodes);
  500. }
  501.  
  502. vmode_t *VID_GetModePtr (int modenum)
  503. {
  504.   vmode_t *pv;
  505.   pv = pvidmodes;
  506.   if (!pv) Sys_Error ("VID_GetModePtr: empty vid mode list");
  507.   while (modenum--)
  508.   {
  509.     pv = pv->pnext;     
  510.     if (!pv) Sys_Error ("VID_GetModePtr: corrupt vid mode list");
  511.   }
  512.   return pv;
  513. }
  514.  
  515. char *VID_ModeInfo (int modenum, char **ppheader)
  516. {
  517.   static char *badmodestr = "Bad mode number";
  518.   vmode_t     *pv;
  519.   pv = VID_GetModePtr (modenum);
  520.   if (!pv)
  521.   {
  522.      if (ppheader) *ppheader = NULL;
  523.      return badmodestr;
  524.   }
  525.   else
  526.   {
  527.       if (ppheader) *ppheader = pv->header;
  528.       return pv->name;
  529.   }
  530. }
  531.  
  532. char *VID_GetModeDescription (int mode)
  533. {
  534.   char        *pinfo, *pheader;
  535.   vmode_t     *pv;
  536.   pv = VID_GetModePtr (mode);
  537.   pinfo = VID_ModeInfo (mode, &pheader);
  538.   return pinfo;
  539. }
  540.  
  541. /*
  542. ================
  543. VID_MenuDraw
  544. ================
  545. */
  546.  
  547. void VID_MenuDraw (void)
  548. {
  549.   qpic_t      *p;
  550.   char        *ptr;
  551.   int         nummodes, i, j, column, row, dup;
  552.   char        temp[100];
  553.  
  554.   vid_wmodes = 0;
  555.   nummodes = VID_NumModes ();
  556.   
  557.   p = Draw_CachePic ("gfx/vidmodes.lmp");
  558.   M_DrawPic ( (320-p->width)/2, 4, p);
  559.  
  560.   for (i=0 ; i<nummodes ; i++)
  561.   {
  562.     if (vid_wmodes < MAX_MODEDESCS)
  563.     {
  564.       ptr = VID_GetModeDescription (i);
  565.       if (ptr)
  566.       {
  567.         dup = 0;
  568.  
  569.         for (j=0 ; j<vid_wmodes ; j++)
  570.         {
  571.           if (!strcmp (modedescs[j].desc, ptr))
  572.           {
  573.             if (modedescs[j].modenum != 0)
  574.             {
  575.               modedescs[j].modenum = i;
  576.               dup = 1;
  577.  
  578.               if (i == vid_modenum) modedescs[j].iscur = 1;
  579.             }
  580.             else
  581.             {
  582.               dup = 1;
  583.             }
  584.             break;
  585.           }
  586.         }
  587.  
  588.         if (!dup)
  589.         {
  590.           modedescs[vid_wmodes].modenum = i;
  591.           modedescs[vid_wmodes].desc = ptr;
  592.           modedescs[vid_wmodes].iscur = 0;
  593.  
  594.           if (i == vid_modenum) modedescs[vid_wmodes].iscur = 1;
  595.  
  596.           vid_wmodes++;
  597.         }
  598.       }
  599.     }
  600.   }
  601.  
  602.   vid_column_size = (vid_wmodes + 2) / 3;
  603.  
  604.   column = 16;
  605.   row = 36;
  606.  
  607.   for (i=0 ; i<vid_wmodes ; i++)
  608.   {
  609.     if (modedescs[i].iscur) M_PrintWhite (column, row, modedescs[i].desc);
  610.     else M_Print (column, row, modedescs[i].desc);
  611.  
  612.     row += 8;
  613.  
  614.     if ((i % vid_column_size) == (vid_column_size - 1))
  615.     {
  616.       column += 13*8;
  617.       row = 36;
  618.     }
  619.   }
  620.  
  621.   M_Print (9*8, 36 + MAX_COLUMN_SIZE * 8 + 8*3, "Press Enter to set mode");
  622.   ptr = VID_GetModeDescription (vid_modenum);
  623.   sprintf (temp, "D to make %s the default", ptr);
  624.   M_Print (6*8, 36 + MAX_COLUMN_SIZE * 8 + 8*5, temp);
  625.   ptr = VID_GetModeDescription ((int)_vid_default_mode.value);
  626.  
  627.   if (ptr)
  628.   {
  629.     sprintf (temp, "Current default is %s", ptr);
  630.     M_Print (7*8, 36 + MAX_COLUMN_SIZE * 8 + 8*6, temp);
  631.   }
  632.  
  633.   M_Print (15*8, 36 + MAX_COLUMN_SIZE * 8 + 8*8, "Esc to exit");
  634.  
  635.   row = 36 + (vid_line % vid_column_size) * 8;
  636.   column = 8 + (vid_line / vid_column_size) * 13*8;
  637.  
  638.   M_DrawCharacter (column, row, 12+((int)(realtime*4)&1));
  639. }
  640.  
  641. /*
  642. ================
  643. VID_MenuKey
  644. ================
  645. */
  646. void VID_MenuKey (int key)
  647. {
  648.   switch (key)
  649.   {
  650.     case K_ESCAPE:
  651.       S_LocalSound ("misc/menu1.wav");
  652.       M_Menu_Options_f ();
  653.       break;
  654.   
  655.     case K_UPARROW:
  656.       S_LocalSound ("misc/menu1.wav");
  657.       vid_line--;
  658.   
  659.       if (vid_line < 0) vid_line = vid_wmodes - 1;
  660.       break;
  661.   
  662.     case K_DOWNARROW:
  663.       S_LocalSound ("misc/menu1.wav");
  664.       vid_line++;
  665.  
  666.       if (vid_line >= vid_wmodes)
  667.       vid_line = 0;
  668.       break;
  669.   
  670.     case K_LEFTARROW:
  671.       S_LocalSound ("misc/menu1.wav");
  672.       vid_line -= vid_column_size;
  673.   
  674.       if (vid_line < 0)
  675.       {
  676.         vid_line += ((vid_wmodes + (vid_column_size - 1)) /
  677.                      vid_column_size) * vid_column_size;
  678.   
  679.         while (vid_line >= vid_wmodes)
  680.                vid_line -= vid_column_size;
  681.       }
  682.       break;
  683.   
  684.     case K_RIGHTARROW:
  685.       S_LocalSound ("misc/menu1.wav");
  686.       vid_line += vid_column_size;
  687.   
  688.       if (vid_line >= vid_wmodes)
  689.       {
  690.         vid_line -= ((vid_wmodes + (vid_column_size - 1)) /
  691.                      vid_column_size) * vid_column_size;
  692.   
  693.         while (vid_line < 0)
  694.           vid_line += vid_column_size;
  695.       }
  696.       break;
  697.   
  698.     case K_ENTER:
  699.       S_LocalSound ("misc/menu1.wav");
  700.       Cvar_SetValue("vid_mode",modedescs[vid_line].modenum);
  701.       vid_modenum=modedescs[vid_line].modenum;
  702.       config_notify=1;
  703.       break;
  704.  
  705.     case 'D':
  706.     case 'd':
  707.       S_LocalSound ("misc/menu1.wav");
  708.       Cvar_SetValue ("_vid_default_mode", modedescs[vid_line].modenum);
  709.       vid_modenum=modedescs[vid_line].modenum;
  710.       break;
  711.  
  712.     default:
  713.       break;
  714.   }
  715. }
  716.