home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quake_src / vid_vga.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-17  |  9.9 KB  |  479 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. // vid_vga.c: VGA-specific DOS video stuff
  22. //
  23.  
  24. // TODO: proper handling of page-swap failure
  25.  
  26. #include <dos.h>
  27.  
  28. #include "quakedef.h"
  29. #include "d_local.h"
  30. #include "dosisms.h"
  31. #include "vid_dos.h"
  32. #include <dpmi.h>
  33.  
  34. extern regs_t regs;
  35.  
  36. int   VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes;
  37. byte  *VGA_pagebase;
  38. vmode_t *VGA_pcurmode;
  39.  
  40. static int    VGA_planar;
  41. static int    VGA_numpages;
  42. static int    VGA_buffersize;
  43.  
  44. void  *vid_surfcache;
  45. int   vid_surfcachesize;
  46.  
  47. int   VGA_highhunkmark;
  48.  
  49. #include "vgamodes.h"
  50.  
  51. #define NUMVIDMODES   (sizeof(vgavidmodes) / sizeof(vgavidmodes[0]))
  52.  
  53. void VGA_UpdatePlanarScreen (void *srcbuffer);
  54.  
  55. static byte backingbuf[48*24];
  56.  
  57. /*
  58. ================
  59. VGA_BeginDirectRect
  60. ================
  61. */
  62. void VGA_BeginDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode, int x,
  63.   int y, byte *pbitmap, int width, int height)
  64. {
  65.   int   i, j, k, plane, reps, repshift;
  66.  
  67.   if (!lvid->direct)
  68.     return;
  69.  
  70.   if (lvid->aspect > 1.5)
  71.   {
  72.     reps = 2;
  73.     repshift = 1;
  74.   }
  75.   else
  76.   {
  77.     reps = 1;
  78.     repshift = 0;
  79.   }
  80.  
  81.   if (pcurrentmode->planar)
  82.   {
  83.     for (plane=0 ; plane<4 ; plane++)
  84.     {
  85.     // select the correct plane for reading and writing
  86.       outportb (SC_INDEX, MAP_MASK);
  87.       outportb (SC_DATA, 1 << plane);
  88.       outportb (GC_INDEX, READ_MAP);
  89.       outportb (GC_DATA, plane);
  90.  
  91.       for (i=0 ; i<(height << repshift) ; i += reps)
  92.       {
  93.         for (k=0 ; k<reps ; k++)
  94.         {
  95.           for (j=0 ; j<(width >> 2) ; j++)
  96.           {
  97.             backingbuf[(i + k) * 24 + (j << 2) + plane] =
  98.                 lvid->direct[(y + i + k) * VGA_rowbytes +
  99.                 (x >> 2) + j];
  100.             lvid->direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
  101.                 pbitmap[(i >> repshift) * 24 +
  102.                 (j << 2) + plane];
  103.           }
  104.         }
  105.       }
  106.     }
  107.   }
  108.   else
  109.   {
  110.     for (i=0 ; i<(height << repshift) ; i += reps)
  111.     {
  112.       for (j=0 ; j<reps ; j++)
  113.       {
  114.         memcpy (&backingbuf[(i + j) * 24],
  115.             lvid->direct + x + ((y << repshift) + i + j) *
  116.              VGA_rowbytes,
  117.             width);
  118.         memcpy (lvid->direct + x + ((y << repshift) + i + j) *
  119.              VGA_rowbytes,
  120.             &pbitmap[(i >> repshift) * width],
  121.             width);
  122.       }
  123.     }
  124.   }
  125. }
  126.  
  127.  
  128. /*
  129. ================
  130. VGA_EndDirectRect
  131. ================
  132. */
  133. void VGA_EndDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode, int x,
  134.   int y, int width, int height)
  135. {
  136.   int   i, j, k, plane, reps, repshift;
  137.  
  138.   if (!lvid->direct)
  139.     return;
  140.  
  141.   if (lvid->aspect > 1.5)
  142.   {
  143.     reps = 2;
  144.     repshift = 1;
  145.   }
  146.   else
  147.   {
  148.     reps = 1;
  149.     repshift = 0;
  150.   }
  151.  
  152.   if (pcurrentmode->planar)
  153.   {
  154.     for (plane=0 ; plane<4 ; plane++)
  155.     {
  156.     // select the correct plane for writing
  157.       outportb (SC_INDEX, MAP_MASK);
  158.       outportb (SC_DATA, 1 << plane);
  159.  
  160.       for (i=0 ; i<(height << repshift) ; i += reps)
  161.       {
  162.         for (k=0 ; k<reps ; k++)
  163.         {
  164.           for (j=0 ; j<(width >> 2) ; j++)
  165.           {
  166.             lvid->direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
  167.                 backingbuf[(i + k) * 24 + (j << 2) + plane];
  168.           }
  169.         }
  170.       }
  171.     }
  172.   }
  173.   else
  174.   {
  175.     for (i=0 ; i<(height << repshift) ; i += reps)
  176.     {
  177.       for (j=0 ; j<reps ; j++)
  178.       {
  179.         memcpy (lvid->direct + x + ((y << repshift) + i + j) *
  180.              VGA_rowbytes,
  181.             &backingbuf[(i + j) * 24],
  182.             width);
  183.       }
  184.     }
  185.   }
  186. }
  187.  
  188.  
  189. /*
  190. ================
  191. VGA_Init
  192. ================
  193. */
  194. void VGA_Init (void)
  195. {
  196.   int   i;
  197.  
  198. // link together all the VGA modes
  199.   for (i=0 ; i<(NUMVIDMODES - 1) ; i++)
  200.   {
  201.     vgavidmodes[i].pnext = &vgavidmodes[i+1];
  202.   }
  203.  
  204. // add the VGA modes at the start of the mode list
  205.   vgavidmodes[NUMVIDMODES-1].pnext = pvidmodes;
  206.   pvidmodes = &vgavidmodes[0];
  207.  
  208.   numvidmodes += NUMVIDMODES;
  209. }
  210.  
  211.  
  212. /*
  213. ================
  214. VGA_WaitVsync
  215. ================
  216. */
  217. void VGA_WaitVsync (void)
  218. {
  219.   while ((inportb (0x3DA) & 0x08) == 0)
  220.     ;
  221. }
  222.  
  223.  
  224. /*
  225. ================
  226. VGA_ClearVideoMem
  227. ================
  228. */
  229. void VGA_ClearVideoMem (int planar)
  230. {
  231.  
  232.   if (planar)
  233.   {
  234.   // enable all planes for writing
  235.     outportb (SC_INDEX, MAP_MASK);
  236.     outportb (SC_DATA, 0x0F);
  237.   }
  238.  
  239.   Q_memset (VGA_pagebase, 0, VGA_rowbytes * VGA_height);
  240. }
  241.  
  242. /*
  243. ================
  244. VGA_FreeAndAllocVidbuffer
  245. ================
  246. */
  247. qboolean VGA_FreeAndAllocVidbuffer (viddef_t *lvid, int allocnewbuffer)
  248. {
  249.   int   tsize, tbuffersize;
  250.  
  251.   if (allocnewbuffer)
  252.   {
  253.   // alloc an extra line in case we want to wrap, and allocate the z-buffer
  254.     tbuffersize = (lvid->rowbytes * (lvid->height + 1)) +
  255.         (lvid->width * lvid->height * sizeof (*d_pzbuffer));
  256.   }
  257.   else
  258.   {
  259.   // just allocate the z-buffer
  260.     tbuffersize = lvid->width * lvid->height * sizeof (*d_pzbuffer);
  261.   }
  262.  
  263.   tsize = D_SurfaceCacheForRes (lvid->width, lvid->height);
  264.  
  265.   tbuffersize += tsize;
  266.  
  267. // see if there's enough memory, allowing for the normal mode 0x13 pixel,
  268. // z, and surface buffers
  269.   if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
  270.      0x10000 * 3) < minimum_memory)
  271.   {
  272.     Con_Printf ("Not enough memory for video mode\n");
  273.     VGA_pcurmode = NULL;  // so no further accesses to the buffer are
  274.                 //  attempted, particularly when clearing
  275.     return false;   // not enough memory for mode
  276.   }
  277.  
  278.   VGA_buffersize = tbuffersize;
  279.   vid_surfcachesize = tsize;
  280.  
  281.   if (d_pzbuffer)
  282.   {
  283.     D_FlushCaches ();
  284.     Hunk_FreeToHighMark (VGA_highhunkmark);
  285.     d_pzbuffer = NULL;
  286.   }
  287.  
  288.   VGA_highhunkmark = Hunk_HighMark ();
  289.  
  290.   d_pzbuffer = Hunk_HighAllocName (VGA_buffersize, "video");
  291.  
  292.   vid_surfcache = (byte *)d_pzbuffer
  293.     + lvid->width * lvid->height * sizeof (*d_pzbuffer);
  294.   
  295.   if (allocnewbuffer)
  296.   {
  297.     lvid->buffer = (void *)( (byte *)vid_surfcache + vid_surfcachesize);
  298.     lvid->conbuffer = lvid->buffer;
  299.   }
  300.  
  301.   return true;
  302. }
  303.  
  304.  
  305. /*
  306. ================
  307. VGA_CheckAdequateMem
  308. ================
  309. */
  310. qboolean VGA_CheckAdequateMem (int width, int height, int rowbytes,
  311.   int allocnewbuffer)
  312. {
  313.   int   tbuffersize;
  314.  
  315.   tbuffersize = width * height * sizeof (*d_pzbuffer);
  316.  
  317.   if (allocnewbuffer)
  318.   {
  319.   // alloc an extra line in case we want to wrap, and allocate the z-buffer
  320.     tbuffersize += (rowbytes * (height + 1));
  321.   }
  322.  
  323.   tbuffersize += D_SurfaceCacheForRes (width, height);
  324.  
  325. // see if there's enough memory, allowing for the normal mode 0x13 pixel,
  326. // z, and surface buffers
  327.   if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
  328.      0x10000 * 3) < minimum_memory)
  329.   {
  330.     return false;   // not enough memory for mode
  331.   }
  332.  
  333.   return true;
  334. }
  335.  
  336.  
  337. /*
  338. ================
  339. VGA_InitMode
  340. ================
  341. */
  342. int VGA_InitMode (viddef_t *lvid, vmode_t *pcurrentmode)
  343. {
  344.   vextra_t    *pextra;
  345.  
  346.   pextra = pcurrentmode->pextradata;
  347.  
  348.   if (!VGA_FreeAndAllocVidbuffer (lvid, pextra->vidbuffer))
  349.     return -1;  // memory alloc failed
  350.  
  351.   if (VGA_pcurmode)
  352.     VGA_ClearVideoMem (VGA_pcurmode->planar);
  353.  
  354. // mode 0x13 is the base for all the Mode X-class mode sets
  355.   regs.h.ah = 0;
  356.   regs.h.al = 0x13;
  357.   dos_int86(0x10);
  358.  
  359.   VGA_pagebase = (void *)real2ptr(0xa0000);
  360.   lvid->direct = (pixel_t *)VGA_pagebase;
  361.  
  362. // set additional registers as needed
  363.   VideoRegisterSet (pextra->pregset);
  364.  
  365.   VGA_numpages = 1;
  366.   lvid->numpages = VGA_numpages;
  367.  
  368.   VGA_width = (lvid->width + 0x1F) & ~0x1F;
  369.   VGA_height = lvid->height;
  370.   VGA_planar = pcurrentmode->planar;
  371.   if (VGA_planar)
  372.     VGA_rowbytes = lvid->rowbytes / 4;
  373.   else
  374.     VGA_rowbytes = lvid->rowbytes;
  375.   VGA_bufferrowbytes = lvid->rowbytes;
  376.   lvid->colormap = host_colormap;
  377.   lvid->fullbright = 256 - LittleLong (*((int *)lvid->colormap + 2048));
  378.  
  379.   lvid->maxwarpwidth = WARP_WIDTH;
  380.   lvid->maxwarpheight = WARP_HEIGHT;
  381.  
  382.   lvid->conbuffer = lvid->buffer;
  383.   lvid->conrowbytes = lvid->rowbytes;
  384.   lvid->conwidth = lvid->width;
  385.   lvid->conheight = lvid->height;
  386.  
  387.   VGA_pcurmode = pcurrentmode;
  388.  
  389.   VGA_ClearVideoMem (pcurrentmode->planar);
  390.  
  391.   if (_vid_wait_override.value)
  392.   {
  393.     Cvar_SetValue ("vid_wait", (float)VID_WAIT_VSYNC);
  394.   }
  395.   else
  396.   {
  397.     Cvar_SetValue ("vid_wait", (float)VID_WAIT_NONE);
  398.   }
  399.  
  400.   D_InitCaches (vid_surfcache, vid_surfcachesize);
  401.  
  402.   return 1;
  403. }
  404.  
  405.  
  406. /*
  407. ================
  408. VGA_SetPalette
  409. ================
  410. */
  411. void VGA_SetPalette(viddef_t *lvid, vmode_t *pcurrentmode, unsigned char *pal)
  412. {
  413.   int shiftcomponents=2;
  414.   int i;
  415.  
  416.   UNUSED(lvid);
  417.   UNUSED(pcurrentmode);
  418.  
  419.   dos_outportb(0x3c8, 0);
  420.   for (i=0 ; i<768 ; i++)
  421.     outportb(0x3c9, pal[i]>>shiftcomponents);
  422. }
  423.  
  424.  
  425. /*
  426. ================
  427. VGA_SwapBuffersCopy
  428. ================
  429. */
  430. void VGA_SwapBuffersCopy (viddef_t *lvid, vmode_t *pcurrentmode,
  431.   vrect_t *rects)
  432. {
  433.  
  434.   UNUSED(pcurrentmode);
  435.  
  436. // TODO: can write a dword at a time
  437. // TODO: put in ASM
  438. // TODO: copy only specified rectangles
  439.   if (VGA_planar)
  440.   {
  441.  
  442.   // TODO: copy only specified rectangles
  443.  
  444.     VGA_UpdatePlanarScreen (lvid->buffer);
  445.   }
  446.   else
  447.   {
  448.     while (rects)
  449.     {
  450.       VGA_UpdateLinearScreen (
  451.           lvid->buffer + rects->x + (rects->y * lvid->rowbytes),
  452.           VGA_pagebase + rects->x + (rects->y * VGA_rowbytes),
  453.           rects->width,
  454.           rects->height,
  455.           lvid->rowbytes,
  456.           VGA_rowbytes);
  457.  
  458.       rects = rects->pnext;
  459.     }
  460.   }
  461. }
  462.  
  463.  
  464. /*
  465. ================
  466. VGA_SwapBuffers
  467. ================
  468. */
  469. void VGA_SwapBuffers (viddef_t *lvid, vmode_t *pcurrentmode, vrect_t *rects)
  470. {
  471.   UNUSED(lvid);
  472.  
  473.   if (vid_wait.value == VID_WAIT_VSYNC)
  474.     VGA_WaitVsync ();
  475.  
  476.   VGA_SwapBuffersCopy (lvid, pcurrentmode, rects);
  477. }
  478.  
  479.