home *** CD-ROM | disk | FTP | other *** search
/ Virtual Reality Homebrewer's Handbook / vr.iso / vr386 / pcxfile.c < prev    next >
C/C++ Source or Header  |  1996-03-19  |  9KB  |  383 lines

  1. /* Load or save a PCX file  */
  2.  
  3. /* originally written by Bernie Roehl, April 1992 based on code by Dave Stampe */
  4.  
  5. // all screen dump code (in other modules) by Dave Stampe
  6.  
  7. // load_pcx and save_pcx redone by Dave Stampe, to support the new
  8. // video driver functions so it'll work in ALL video modes.  24/12/93
  9. // ditto for load_pcx, 29/12/93
  10.  
  11.  
  12. /*
  13.  This code is part of the VR-386 project, created by Dave Stampe.
  14.  VR-386 is a desendent of REND386, created by Dave Stampe and
  15.  Bernie Roehl.  Almost all the code has been rewritten by Dave
  16.  Stampre for VR-386.
  17.  
  18.  Copyright (c) 1994 by Dave Stampe:
  19.  May be freely used to write software for release into the public domain
  20.  or for educational use; all commercial endeavours MUST contact Dave Stampe
  21.  (dstampe@psych.toronto.edu) for permission to incorporate any part of
  22.  this software or source code into their products!  Usually there is no
  23.  charge for under 50-100 items for low-cost or shareware products, and terms
  24.  are reasonable.  Any royalties are used for development, so equipment is
  25.  often acceptable payment.
  26.  
  27.  ATTRIBUTION:  If you use any part of this source code or the libraries
  28.  in your projects, you must give attribution to VR-386 and Dave Stampe,
  29.  and any other authors in your documentation, source code, and at startup
  30.  of your program.  Let's keep the freeware ball rolling!
  31.  
  32.  DEVELOPMENT: VR-386 is a effort to develop the process started by
  33.  REND386, improving programmer access by rewriting the code and supplying
  34.  a standard API.  If you write improvements, add new functions rather
  35.  than rewriting current functions.  This will make it possible to
  36.  include you improved code in the next API release.  YOU can help advance
  37.  VR-386.  Comments on the API are welcome.
  38.  
  39.  CONTACT: dstampe@psych.toronto.edu
  40. */
  41.  
  42.  
  43. #include <stdio.h>
  44. #include <dos.h>
  45. #include <alloc.h>
  46.  
  47. #include "f3dkitd.h"  /* reset_hdwe(), read_screen_line */
  48. #include "vr_api.h"
  49. #include "pcdevice.h" /* left_page, right_page */
  50.  
  51. // PCX READ?WRITE COMPRESSED FORMATS
  52.  
  53.  
  54. struct PCXHEADER{
  55.     unsigned char manu, hard, encod, bitpx;
  56.     unsigned int x1, y1, x2, y2;
  57.     unsigned int hres, vres;
  58.     unsigned char palette[48];
  59.     unsigned char vmode, nplanes;
  60.     unsigned int bytesPerLine;
  61.     char unused[128-68];
  62.        } ;
  63.  
  64.  
  65. static int getbyte(int *c, int *count, FILE *in)
  66. {
  67.     if (feof(in)) return EOF;
  68.     *c = getc(in) & 0xFF;
  69.     if ((*c & 0xC0) == 0xC0) {
  70.         *count = *c & 0x3F;
  71.         if (feof(in)) return EOF;
  72.         *c = getc(in) & 0xFF;
  73.     }
  74.     else
  75.         *count = 1;
  76.     return NULL;
  77. }
  78.  
  79. static void putbyte(int c, int count, FILE *out)
  80. {
  81.     if (count == 0)
  82.         return;
  83.     if (count > 1 || (c & 0xC0) == 0xC0)
  84.         putc(count | 0xC0, out);
  85.     putc(c, out);
  86. }
  87.  
  88.  
  89.  
  90. // OLD VERSION, 320x200,256 ONLY: KEPT FOR OLD VIDEO DRIVERS
  91.  
  92. static unsigned char far *screen = MK_FP(0xA000, 0);
  93.  
  94. static void write_line(char far *buffer, char far *scr)
  95. {
  96.     int i, plane;
  97.     char *add, *buff;
  98.  
  99.     for (plane = 0; plane < 4; ++plane)
  100.     {
  101.         outport(0x3C4, (1<<(plane+8))+2);
  102.         add = scr;
  103.         buff = &buffer[plane];
  104.         for (i = 0; i < 80; ++i)
  105.         {
  106.             *add++ = *buff;
  107.             buff += 4;
  108.         }
  109.     }
  110. }
  111.  
  112. static oldloadpcx(FILE *in, int page)
  113. {
  114.     int c, count;
  115.     char buff[330];
  116.     char *buffer = &buff[0];
  117.     char *scr = &screen[16000*page];
  118.     unsigned nread = 0;
  119.  
  120.     reset_hdwe();
  121.     fseek(in, 128L, SEEK_SET); /* skip PCX header */
  122.     while (getbyte(&c, &count, in) != EOF)
  123.         while (count--)
  124.         {
  125.             *buffer++ = c;
  126.             if (++nread == 320)
  127.             {
  128.                 write_line(&buff[0],scr);
  129.                 buffer = &buff[0];
  130.                 nread = 0;
  131.                 scr += 80;
  132.             }
  133.         }
  134.     return 0;
  135. }
  136.  
  137.  
  138.  
  139. // NEW: USE VIDEO DRIVER FUNCTION (Dave Stampe)
  140.  
  141.  
  142. load_pcx(FILE *in, int page)
  143. {
  144.   int i,j;
  145.   int c, count;
  146.   int line = screeninfo->ymin;
  147.   unsigned nread = 0;
  148.   char *buff;
  149.   struct PCXHEADER hd;
  150.  
  151.   set_drawpage(page);    // which page to access
  152.  
  153.   j = read_video_line(0,NULL);    // number of pixels
  154.  
  155.   if(j==FP_OFF(screeninfo))    // old driver? (stub test)
  156.     {
  157.       oldloadpcx(in, page);
  158.       return 0;
  159.     }
  160.  
  161.   fread(&hd, 128, 1, in);    // get header
  162.  
  163.   j = hd.bytesPerLine;
  164.  
  165.   buff = malloc(j);             // get buffer
  166.   if(!buff) return -1;
  167.  
  168.   memset(buff,0,j);        // zero buffer
  169.   i = 0;
  170.  
  171.   while (getbyte(&c, &count, in) != EOF)
  172.     while (count--)
  173.       {
  174.     buff[i++] = c;
  175.     if (j == i)
  176.       {
  177.         write_video_line(&buff[0],line++);
  178.         i = 0;
  179.       }
  180.       }
  181.    return 0;
  182. }
  183.  
  184.  
  185. // PCX header for write
  186.  
  187. struct PCXHEADER pccHeader =  {
  188.         10, 5, 1, 8, 0, 0, 319, 199, 75, 75,  // header
  189.            { 0 },                                // zeroed palette
  190.          0x13, 1, 320, 0 };                  // rest
  191.  
  192.  
  193.  
  194. /* NEED A FUNCTION FOR THIS IN VIDEO DRIVER -- OLD CODE */
  195.  
  196.  
  197. static char get_pixel(unsigned int adr, int page)
  198. {
  199.     outport(0x3CE, ((adr&3)<<8)+4); /* select plane to read */
  200.     return *(char *)(MK_FP((0xA000+(1008*page)),adr>>2));
  201. }
  202.  
  203.  
  204. oldpcxsave(FILE *out, int page)
  205. {
  206.     unsigned c, oldc, count;
  207.     unsigned nput = 1;
  208.     union REGS r;
  209.  
  210.     reset_hdwe();
  211.     fwrite(&pccHeader, 128, 1, out);
  212.     count = 1;
  213.     oldc = get_pixel(0,page);
  214.     while ((nput>>2) < 16000)
  215.     {
  216.         c = get_pixel(nput++, page);
  217.         if (c != oldc)
  218.         {
  219.             putbyte(oldc, count, out);
  220.             oldc = c;
  221.             count = 1;
  222.         }
  223.         else if (++count >= 63)
  224.         {
  225.             putbyte(oldc, count, out);
  226.             count = 0;
  227.         }
  228.     }
  229.     putbyte(oldc, count, out);
  230.  
  231.     putc(0x0C, out);
  232.     for (count = 0; count < 256; ++count)
  233.     {
  234.         r.x.ax = 0x1015;
  235.         r.x.bx = count; /* write pallete */
  236.         int86(0x10, &r, &r);
  237.         putc(r.h.dh<<2, out);
  238.         putc(r.h.ch<<2, out);
  239.         putc(r.h.cl<<2, out);
  240.     }
  241.     return 0;
  242. }
  243.  
  244.  
  245.  
  246. // NEW: USE VIDEO DRIVER FUNCTION (Dave Stampe)
  247.  
  248.  
  249.  
  250. save_pcx(FILE *out, int page)
  251. {
  252.  unsigned c, oldc, count;
  253.  union REGS r;
  254.  unsigned i,j,k;
  255.  
  256.  char *buff;
  257.  
  258.  set_drawpage(page);    // which page to access
  259.  
  260.  j = read_video_line(0,NULL);    // number of pixels
  261.  
  262.  if(j==FP_OFF(screeninfo))    // old driver?
  263.    {
  264.      oldpcxsave(out, page);
  265.      return 0;
  266.    }
  267.  
  268.  buff = malloc(j);         // get buffer
  269.  if(!buff) return -1;
  270.  
  271.  pccHeader.x1 = screeninfo->xmin;   // set PCX file size
  272.  pccHeader.y1 = screeninfo->ymin;
  273.  pccHeader.bytesPerLine = screeninfo->xmax - screeninfo->xmin+1;
  274.  pccHeader.y1 = screeninfo->ymin;
  275.  pccHeader.x2 = screeninfo->xmax;
  276.  pccHeader.y2 = screeninfo->ymax-1;
  277.  
  278.  fwrite(&pccHeader, 128, 1, out);
  279.                      // write out each line seperately
  280.  for(i=screeninfo->ymin;i<screeninfo->ymax;i++)
  281.    {
  282.      read_video_line(buff, i);
  283.  
  284.      count = 1;
  285.      c = oldc = buff[0];
  286.      for(k=1;k<j;k++)
  287.     {
  288.        c = buff[k];
  289.        if (c != oldc)
  290.          {
  291.            putbyte(oldc, count, out);
  292.            oldc = c;
  293.            count = 1;
  294.          }
  295.        else if (++count >= 63)
  296.          {
  297.            putbyte(oldc, count, out);
  298.            count = 0;
  299.          }
  300.     }
  301.      putbyte(oldc, count, out);
  302.    }
  303.  
  304.    free(buff);
  305.    putc(0x0C, out);
  306.    buff = malloc(screeninfo->colors*3);
  307.  
  308.    if(buff==NULL)
  309.      for (count = 0; count <256;  ++count)   // default read;
  310.     {
  311.        r.x.ax = 0x1015;
  312.        r.x.bx = count; /* write pallete */
  313.        int86(0x10, &r, &r);
  314.        putc(r.h.dh<<2, out);
  315.        putc(r.h.ch<<2, out);
  316.        putc(r.h.cl<<2, out);
  317.     }
  318.    else
  319.      {
  320.       read_DAC_colors(buff,screeninfo->colors,0);
  321.       j = screeninfo->colors;
  322.       k = 0;
  323.       for (i = 0; i<j; i++)
  324.     {
  325.       putc(buff[k++]<<2, out);
  326.       putc(buff[k++]<<2, out);
  327.       putc(buff[k++]<<2, out);
  328.     }
  329.       for(;i<256;i++)        // need to complete buffer
  330.     {
  331.       putc(0<<2, out);
  332.       putc(0<<2, out);
  333.       putc(0<<2, out);
  334.     }
  335.      }
  336.  
  337.  free(buff);
  338.  
  339.  return 0;
  340. }
  341.  
  342. ///////////// MONO/STEREO SCREEN DUMP
  343.  
  344.  
  345. int screendump(void) /* alt-F10 */
  346. {
  347.   char filename[30] = "scrn0000.pcx";
  348.   char far *buffer;
  349.   FILE *out;
  350.   int i;
  351.  
  352.   for (i = 0; i < 30; i++) /* find a screendump number */
  353.     {
  354.       sprintf(filename,"scrn%c%d.pcx",
  355.       stereo_type==SWITCHED ? 'L' : '_' , i+1);
  356.       if ((out=fopen(filename,"rb"))==NULL) goto doit;
  357.         fclose(out);
  358.     }
  359.   return 3;
  360.  
  361. doit:
  362.   if(stereo_type!=SWITCHED)
  363.     {
  364.       if ((out = fopen(filename, "wb")) == NULL) return 3;
  365.       save_pcx(out, current_video_page);
  366.       fclose(out);
  367.       return 0;
  368.     }
  369.   else
  370.     {
  371.       filename[4] = 'L';
  372.       if ((out = fopen(filename, "wb")) == NULL) return 3;
  373.       save_pcx(out, left_page);
  374.       fclose(out);
  375.       filename[4] = 'R';
  376.       if ((out = fopen(filename, "wb")) == NULL) return 3;
  377.       save_pcx(out, right_page);
  378.       fclose(out);
  379.       return 0;
  380.     }
  381. }
  382.  
  383.