home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 350_01 / pcx_file.c < prev    next >
C/C++ Source or Header  |  1991-12-01  |  50KB  |  1,378 lines

  1. /*
  2.  *************************************************************************
  3.  *
  4.  *  PCX_FILE.C - PCX_LIB Library Image File Functions
  5.  *
  6.  *  Version:    1.00C
  7.  *
  8.  *  History:    91/02/14 - Created
  9.  *              91/04/01 - Release 1.00A
  10.  *              91/04/03 - Fixed "segread" call.
  11.  *              91/04/07 - Release 1.00B
  12.  *              91/11/18 - Fixed "pcx_init_palette" and "pcx_write_extpal"
  13.  *                         for large memory model.
  14.  *                       - Made default EGA palette register values
  15.  *                           array "_far".
  16.  *              91/12/01 - Release 1.00C
  17.  *
  18.  *  Compiler:   Microsoft C V6.0
  19.  *
  20.  *  Author:     Ian Ashdown, P.Eng.
  21.  *              byHeart Software
  22.  *              620 Ballantree Road
  23.  *              West Vancouver, B.C.
  24.  *              Canada V7S 1W3
  25.  *              Tel. (604) 922-6148
  26.  *              Fax. (604) 987-7621
  27.  *
  28.  *  Copyright:  Public Domain
  29.  *
  30.  *************************************************************************
  31.  */
  32.  
  33. /*
  34.  *************************************************************************
  35.  *
  36.  *  PORTABILITY NOTES
  37.  *
  38.  *  1.  While this program is written in ANSI C, it uses a number of 
  39.  *      function calls that are specific to the Microsoft C V6.0 library.
  40.  *      These are documented as follows for the purposes of porting this
  41.  *      program to other compilers and/or processors: 
  42.  *
  43.  *          _ffree      - "free" for small model / far data
  44.  *          _fmalloc    - "malloc" for small model / far data
  45.  *          _fmemcpy    - "memcpy" for small model / far data
  46.  *          int86       - execute 80x86 interrupt routine
  47.  *          int86x      - execute 80x86 interrupt routine (far data)
  48.  *          outpw       - output word to 80x86 I/O port
  49.  *
  50.  *  2.  When porting this program to other processors, remember that words
  51.  *      are stored by 80x86-based machines in the big-endian format.  That
  52.  *      is, the eight least significant bits (lower byte) are stored
  53.  *      first, followed by the eight most significant bits (upper byte).
  54.  *      If PCX-format files are transferred to little-endian machines
  55.  *      (such as those based on 680x0 and Z8000 processors), the order of
  56.  *      bytes within each word will have to be reversed before they can 
  57.  *      be interpreted.  (This applies to the file header only, since the
  58.  *      encoded image data and optional 256-color palette are stored as
  59.  *      bytes.)
  60.  *
  61.  * 3.   MS-DOS does not recognize the 720 x 348 graphics mode of the
  62.  *      Hercules monochrome display adapter.  Therefore, the constant
  63.  *      PCX_HERC should never be passed as a video mode parameter to any
  64.  *      BIOS service routine.
  65.  *
  66.  *      The Microsoft C compiler includes a "video mode" parameter
  67.  *      definition (_HERCMONO) that is defined as 0x08.  This is a
  68.  *      reserved MS-DOS video mode that is apparently used internally by
  69.  *      the ROM BIOS.  It can, however, be passed to the Microsoft C
  70.  *      library function "_setvideomode" to force the Hercules display
  71.  *      adapter into graphics mode.
  72.  *
  73.  *      Most other MS-DOS C compilers offer similar library functions to
  74.  *      force the Hercules monochrome display adapter into its 720 x 348
  75.  *      graphics mode.
  76.  *
  77.  ************************************************************************* 
  78.  */
  79.  
  80. /*      INCLUDE FILES                                                   */
  81.  
  82. #include <stdio.h>
  83. #include <stdlib.h>
  84. #include <string.h>
  85. #include <conio.h>
  86. #include <malloc.h>
  87. #include <dos.h>
  88. #include <graph.h>
  89. #include "pcx_int.h"
  90.  
  91. /*      FORWARD REFERENCES                                              */
  92.  
  93. static BOOL pcx_encode(int, int, FILE *);
  94. static BOOL pcx_init_palette(PCX_PAL *, int);
  95. static BOOL pcx_write_extpal(FILE *);
  96. static BOOL pcx_write_line(unsigned char *, int, FILE *);
  97. static BOOL pcx_write_init(PCX_WORKBLK *, int, int, int, int);
  98.  
  99. static void pcx_get_cga(PCX_WORKBLK *, unsigned char _far *, int);
  100. static void pcx_get_ega(PCX_WORKBLK *, unsigned char _far *, int);
  101. static void pcx_get_herc(PCX_WORKBLK *, unsigned char _far *, int);
  102. static void pcx_get_vga(PCX_WORKBLK *, unsigned char _far *, int);
  103.  
  104. /*      GLOBALS                                                         */
  105.  
  106. /* Default EGA palette register values                                  */
  107.  
  108. static BYTE _far pcx_EGA_DefPal_1[16] =         /* Modes 0x0d and 0x0e  */
  109. {
  110.   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13,
  111.   0x14, 0x15, 0x16, 0x17
  112. };
  113.  
  114. static BYTE _far pcx_EGA_DefPal_2[16] =         /* Mode 0x0f            */
  115. {
  116.   0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
  117.   0x00, 0x18, 0x00, 0x00
  118. };
  119.  
  120. static BYTE _far pcx_EGA_DefPal_3[16] =         /* Mode 0x10            */
  121. {
  122.   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 
  123.   0x3c, 0x3d, 0x3e, 0x3f
  124. };
  125.  
  126. /*      PUBLIC FUNCTIONS                                                */
  127.  
  128. /*
  129.  *************************************************************************
  130.  *
  131.  *  PCX_WRITE - Write PCX File
  132.  *
  133.  *  Purpose:    To write a PCX-format image file from an image stored in
  134.  *              a video buffer.  The image is assumed to start in the
  135.  *              upper left corner of the screen.
  136.  *
  137.  *  Setup:      BOOL pcx_write
  138.  *              (
  139.  *                char *fname,
  140.  *                int vmode,
  141.  *                int page,
  142.  *                int width,
  143.  *                int height,
  144.  *              )
  145.  *
  146.  *  Where:      fname is a PCX image file name.
  147.  *              vmode is the MS-DOS video mode.  Valid values are:
  148.  *
  149.  *                PCX_HERC -    720 x 348 Hercules monochrome
  150.  *                0x04 -        320 x 200 4-color CGA
  151.  *                0x05 -        320 x 200 4-color CGA (color burst off)
  152.  *                0x06 -        640 x 200 2-color CGA
  153.  *                0x0d -        320 x 200 16-color EGA/VGA
  154.  *                0x0e -        640 x 200 16-color EGA/VGA
  155.  *                0x0f -        640 x 350 2-color EGA/VGA
  156.  *                0x10 -        640 x 350 16-color EGA/VGA
  157.  *                0x11 -        640 x 480 2-color VGA
  158.  *                0x12 -        640 x 480 16-color VGA
  159.  *                0x13 -        320 x 200 256-color VGA
  160.  *
  161.  *              page is the video display page number.  Valid values are:
  162.  *
  163.  *                Mode PCX_HERC - 0 or 1
  164.  *                Mode 0x0d     - 0 to 7
  165.  *                Mode 0x0e     - 0 to 3
  166.  *                Mode 0x0f     - 0 or 1
  167.  *                Mode 0x10     - 0 or 1
  168.  *                All Other     - 0
  169.  *
  170.  *              width is the image width in pixels.
  171.  *              height is the image height in pixels.
  172.  *
  173.  *  Return:     TRUE if successful; otherwise FALSE.
  174.  *
  175.  *************************************************************************
  176.  */
  177.  
  178. BOOL pcx_write
  179. (
  180.   char *fname,
  181.   int vmode,
  182.   int page,
  183.   int width,
  184.   int height
  185. )
  186. {
  187.   int bpline;                   /* Number of bytes per scan line        */
  188.   int line_num;                 /* Scan line number                     */
  189.   unsigned char *linep;         /* Image scan line buffer pointer       */
  190.   BOOL status = TRUE;           /* Return status                        */
  191.   PCX_WORKBLK *wbp;             /* PCX image file workblock pointer     */
  192.  
  193.   /* Open a PCX image file workblock                                    */
  194.  
  195.   if ((wbp = pcx_open(fname, TRUE)) == (PCX_WORKBLK *) NULL)
  196.     return (FALSE);
  197.  
  198.   /* Initialize the workblock for writing                               */
  199.  
  200.   if (pcx_write_init(wbp, vmode, page, width, height) == FALSE)
  201.     status = FALSE;
  202.  
  203.   /* Calculate number of bytes per line (for all color planes)          */
  204.  
  205.   bpline = wbp->header.bppscan * wbp->header.nplanes;
  206.  
  207.   /* Allocate a scan line buffer                                        */
  208.  
  209.   if (status == TRUE)
  210.     if ((linep = (unsigned char *) malloc(bpline)) == (unsigned char *)
  211.         NULL)
  212.       status = FALSE;
  213.  
  214.   /* Write the file header to the file                                  */
  215.  
  216.   if (status == TRUE)
  217.     if (fwrite(&(wbp->header), sizeof(PCX_HDR), 1, wbp->fp) != 1)
  218.       status = FALSE;
  219.  
  220.   /* Write the encoded image data to the file                           */
  221.  
  222.   if (status == TRUE)
  223.   {
  224.     for (line_num = 0; line_num <= (int) wbp->header.ylr; line_num++)
  225.     {
  226.       /* Get the current video buffer scan line                         */
  227.  
  228.       wbp->pcx_funcp(wbp, (unsigned char _far *) linep, line_num);
  229.  
  230.       /* Encode the scan line and write it to the file                  */
  231.  
  232.       if (pcx_write_line(linep, bpline, wbp->fp) == FALSE)
  233.       {
  234.         status = FALSE;
  235.         break;
  236.       }
  237.     }
  238.   }
  239.  
  240.   if (vmode == 0x13)    /* Is a 256-color palette supported ?           */
  241.   {
  242.     /* Write the extended palette to the file                           */
  243.  
  244.     if (status == TRUE)
  245.       if (pcx_write_extpal(wbp->fp) == FALSE)
  246.         status = FALSE;
  247.   }
  248.  
  249.   if (pcx_close(wbp) == FALSE)  /* Close the PCX workblock              */
  250.     status = FALSE;
  251.  
  252.   free(linep);          /* Free the scan line buffer                    */
  253.  
  254.   /* Remove the PCX image file if an error occurred                     */
  255.  
  256.   if (status == FALSE)
  257.     (void) remove(fname);
  258.  
  259.   return (status);
  260. }
  261.  
  262. /*
  263.  *************************************************************************
  264.  *
  265.  *  PCX_INIT_DSA - Initialize Dynamic Save Area
  266.  *
  267.  *  Purpose:    To set up a Video Services Primary Pointer Table and an
  268.  *              associated Dynamic Save Area where BIOS service "Set All
  269.  *              Palette Registers" (function 0x02) can store the EGA color
  270.  *              palette registers settings after it updates them.
  271.  *
  272.  *  Setup:      BOOL pcx_init_dsa
  273.  *              (
  274.  *                PCX_VSB **vsbpp
  275.  *              )
  276.  *
  277.  *  Where:      vsbp is a pointer to where a pointer to an instantiated
  278.  *              PCX_VSB structure is to be returned.
  279.  *
  280.  *  Return:     TRUE if successful; otherwise FALSE.
  281.  *
  282.  *  Note:       The EGA display adapter color palette registers are
  283.  *              write-only.  In order to save the current color palette
  284.  *              with a PCX-format image file by calling "pcx_write", you
  285.  *              must call this function BEFORE you display the image in
  286.  *              the following MS-DOS video modes:
  287.  *
  288.  *                0x0d  - 320 x 200 16-color EGA
  289.  *                0x0e  - 640 x 200 16-color EGA
  290.  *                0x0f  - 640 x 350 2-color EGA
  291.  *                0x10  - 640 x 350 16-color EGA
  292.  *
  293.  *              You MUST call "pcx_free_dsa" upon completion of your
  294.  *              program.   See the function header of "pcx_init_palette"
  295.  *              for more information.
  296.  *
  297.  *************************************************************************
  298.  */
  299.  
  300. BOOL pcx_init_dsa
  301. (
  302.   PCX_VSB **vsbpp
  303. )
  304. {
  305.   unsigned char _far *dsap;     /* Dynamic Save Area pointer            */
  306.   PCX_VSB *vsbp;                /* Video services data save buffer ptr  */
  307.  
  308.   *vsbpp = (PCX_VSB *) NULL;    /* Initialize returned pointer          */
  309.  
  310.   /* Allocate a Dynamic Save Area buffer                                */
  311.  
  312.   if ((dsap = (unsigned char _far *) _fmalloc(sizeof(unsigned char) *
  313.       256)) == (unsigned char _far *) NULL)
  314.     return (FALSE);
  315.  
  316.   /* Allocate a BIOS video services data save buffer                    */
  317.  
  318.   if ((vsbp = (PCX_VSB *) malloc(sizeof(PCX_VSB))) == (PCX_VSB *) NULL)
  319.   {
  320.     _ffree(dsap);       /* Free the Dynamic Save Area buffer            */
  321.     return (FALSE);
  322.   }
  323.  
  324.   /* Save the existing Primary Pointer Table pointer                    */
  325.  
  326.   vsbp->prev_pptp = *((struct pcx_ppt _far * _far *) 0x004000a8L);
  327.  
  328.   /* Copy the existing Primary Pointer Table into the buffer            */
  329.  
  330.   (void) _fmemcpy((struct pcx_ppt _far *) &(vsbp->pcx_ppt),
  331.       vsbp->prev_pptp, sizeof(struct pcx_ppt));
  332.  
  333.   vsbp->pcx_ppt.dsap = dsap;    /* Update the Dynamic Save Area ptr     */
  334.  
  335.   /* Update the Primary Pointer Table pointer in the Video Save Table   */
  336.  
  337.   *((struct pcx_ppt _far * _far *) 0x004000a8L) = &(vsbp->pcx_ppt);
  338.  
  339.   *vsbpp = vsbp;        /* Return Video Services data save buffer ptr   */
  340.  
  341.   return (TRUE);
  342. }
  343.  
  344. /*
  345.  *************************************************************************
  346.  *
  347.  *  PCX_FREE_DSA - Release Dynamic Save Area
  348.  *
  349.  *  Purpose:    To release memory allocated to the Video Services Primary
  350.  *              Pointer Table and associated Dynamic Save Area and reset
  351.  *              the pointer in the Video Save Table.
  352.  *
  353.  *  Setup:      void pcx_free_dsa
  354.  *              (
  355.  *                PCX_VSB *vsbp
  356.  *              )
  357.  *
  358.  *  Where:      vsbp is a pointer to a PCX_VSB structure that was
  359.  *                previously allocated and initialized by "pcx_init_dsa".
  360.  *
  361.  *  Note:       You MUST call this function on completion of your program
  362.  *              if you previously called "pcx_init_dsa".  Failure to do so
  363.  *              will leave the system in an unstable state.  See the
  364.  *              function header of "pcx_init_palette" for more
  365.  *              information.
  366.  *
  367.  *************************************************************************
  368.  */
  369.  
  370. void pcx_free_dsa
  371. (
  372.   PCX_VSB *vsbp
  373. )
  374. {
  375.   /* Restore the previous primary pointer table pointer                 */
  376.  
  377.   *((struct pcx_ppt _far * _far *) 0x004000a8L) = vsbp->prev_pptp;
  378.  
  379.   _ffree(vsbp->pcx_ppt.dsap);   /* Free the Dynamic Save Area           */
  380.  
  381.   free(vsbp);   /* Free the Video Services data save buffer             */
  382. }
  383.  
  384. /*      PRIVATE FUNCTIONS                                               */
  385.  
  386. /*
  387.  *************************************************************************
  388.  *
  389.  *  PCX_WRITE_INIT - Initialize PCX Workblock For Writing
  390.  *
  391.  *  Purpose:    To initialize a PCX image file workblock for writing.
  392.  *
  393.  *  Setup:      static BOOL pcx_write_init
  394.  *              (
  395.  *                PCX_WORKBLK *wbp,
  396.  *                int vmode,
  397.  *                int page,
  398.  *                int width,
  399.  *                int height
  400.  *              )
  401.  *
  402.  *  Where:      wbp is a PCX workblock pointer.
  403.  *              vmode is the MS-DOS video mode.  Valid values are:
  404.  *
  405.  *                0x04 -        320 x 200 4-color CGA
  406.  *                0x05 -        320 x 200 4-color CGA (color burst off)
  407.  *                0x06 -        640 x 200 2-color CGA
  408.  *                Ox07 -        720 x 348 Hercules monochrome
  409.  *                0x0d -        320 x 200 16-color EGA/VGA
  410.  *                0x0e -        640 x 200 16-color EGA/VGA
  411.  *                0x0f -        640 x 350 2-color EGA/VGA
  412.  *                0x10 -        640 x 350 16-color EGA/VGA
  413.  *                0x11 -        640 x 480 2-color VGA
  414.  *                0x12 -        640 x 480 16-color VGA
  415.  *                0x13 -        320 x 200 256-color VGA
  416.  *
  417.  *              page is the video display page number.  Valid values are:
  418.  *
  419.  *                Mode PCX_HERC - 0 or 1
  420.  *                Mode 0x0d     - 0 to 7
  421.  *                Mode 0x0e     - 0 to 3
  422.  *                Mode 0x0f     - 0 or 1
  423.  *                Mode 0x10     - 0 or 1
  424.  *                All Other     - 0
  425.  *
  426.  *              width is the image width in pixels.
  427.  *              height is the image height in pixels.
  428.  *
  429.  *  Return:     TRUE if successful; otherwise FALSE.
  430.  *
  431.  *************************************************************************
  432.  */
  433.  
  434. static BOOL pcx_write_init
  435. (
  436.   PCX_WORKBLK *wbp,
  437.   int vmode,
  438.   int page,
  439.   int width,
  440.   int height
  441. )
  442. {
  443.   int max_width;        /* Maximum image width                          */
  444.   int max_height;       /* Maximum image height                         */
  445.   int shift;            /* Mask shift value                             */
  446.   BOOL status = TRUE;   /* Return status                                */
  447.   PCX_HDR *hdrp;        /* File header buffer pointer                   */
  448.  
  449.   /* Initialize the display page address offset                         */
  450.  
  451.   wbp->page_offset = (unsigned long) 0L;
  452.  
  453.   hdrp = &(wbp->header);        /* Initialize the file header pointer   */
  454.  
  455.   /* Initialize the header constants                                    */
  456.  
  457.   hdrp->pcx_id = 0x0a;          /* PCX format identifier                */
  458.   hdrp->version = 5;            /* Version number                       */
  459.   hdrp->encoding = 1;           /* Encoding format (run-length)         */
  460.   hdrp->xul = 0;                /* Upper left x-position                */
  461.   hdrp->yul = 0;                /* Upper left y-position                */
  462.   hdrp->reserved = 0;           /* (Used to be video mode)              */
  463.   hdrp->palette_type = 1;       /* Color or b&w palette type            */
  464.  
  465.   memset(hdrp->filler, 0, sizeof(hdrp->filler));        /* Padding      */
  466.  
  467.   /* Initialize the video mode-dependent parameters                     */
  468.  
  469.   switch (vmode)
  470.   {
  471.     case PCX_HERC:      /* 720 x 348 Hercules monochrome                */
  472.  
  473.       max_width = min(width, 720);      /* Maximum image width          */
  474.       max_height = min(height, 348);    /* Maximum image height         */
  475.  
  476.       hdrp->bppixel = 1;                /* Bits per pixel               */
  477.       hdrp->horz_res = 720;             /* Horizontal resolution        */
  478.       hdrp->vert_res = 348;             /* Vertical resolution          */
  479.       hdrp->nplanes = 1;                /* Number of color planes       */
  480.  
  481.       /* Maximum two pages supported                                    */
  482.  
  483.       wbp->page_offset = 0x08000000L * (unsigned long) page;
  484.  
  485.       /* Calculate number of bytes to copy                              */
  486.  
  487.       wbp->num_bytes = (max_width + 7) >> 3;
  488.  
  489.       shift = (max_width & 7);  /* Calculate mask shift value           */
  490.  
  491.       wbp->pcx_funcp = pcx_get_herc;    /* Set display capture fcn ptr  */
  492.  
  493.       break;
  494.  
  495.     case 0x04:          /* 320 x 200 4-color CGA                        */
  496.     case 0x05:          /* 320 x 200 4-color CGA (color burst off)      */
  497.  
  498.       max_width = min(width, 320);      /* Maximum image width          */
  499.       max_height = min(height, 200);    /* Maximum image height         */
  500.  
  501.       hdrp->bppixel = 2;                /* Bits per pixel               */
  502.       hdrp->horz_res = 320;             /* Horizontal resolution        */
  503.       hdrp->vert_res = 200;             /* Vertical resolution          */
  504.       hdrp->nplanes = 1;                /* Number of color planes       */
  505.  
  506.       /* Calculate number of bytes to copy                              */
  507.  
  508.       wbp->num_bytes = (max_width + 3) >> 2;
  509.  
  510.       shift = (max_width & 3) << 1;     /* Calculate mask shift value   */
  511.  
  512.       wbp->pcx_funcp = pcx_get_cga;     /* Set display capture fcn ptr  */
  513.  
  514.       break;
  515.  
  516.     case 0x06:          /* 640 x 200 2-color CGA                        */
  517.  
  518.       max_width = min(width, 640);      /* Maximum image width          */
  519.       max_height = min(height, 200);    /* Maximum image height         */
  520.  
  521.       hdrp->bppixel = 1;                /* Bits per pixel               */
  522.       hdrp->horz_res = 640;             /* Horizontal resolution        */
  523.       hdrp->vert_res = 200;             /* Vertical resolution          */
  524.       hdrp->nplanes = 1;                /* Number of color planes       */
  525.  
  526.       /* Calculate number of bytes to copy                              */
  527.  
  528.       wbp->num_bytes = (max_width + 7) >> 3;
  529.  
  530.       shift = (max_width & 7);  /* Calculate mask shift value           */
  531.  
  532.       wbp->pcx_funcp = pcx_get_cga;     /* Set display capture fcn ptr  */
  533.  
  534.       break;
  535.  
  536.     case 0x0d:          /* 320 x 200 16-color EGA/VGA                   */
  537.  
  538.       max_width = min(width, 320);      /* Maximum image width          */
  539.       max_height = min(height, 200);    /* Maximum image height         */
  540.  
  541.       hdrp->bppixel = 1;                /* Bits per pixel               */
  542.       hdrp->horz_res = 320;             /* Horizontal resolution        */
  543.       hdrp->vert_res = 200;             /* Vertical resolution          */
  544.       hdrp->nplanes = 4;                /* Number of color planes       */
  545.  
  546.       /* Maximum eight display pages supported                          */
  547.  
  548.       wbp->page_offset = 0x02000000L * (unsigned long) page;
  549.  
  550.       /* Calculate number of bytes to copy                              */
  551.  
  552.       wbp->num_bytes = (max_width + 7) >> 3;
  553.  
  554.       shift = (max_width & 7);  /* Calculate mask shift value           */
  555.  
  556.       wbp->pcx_funcp = pcx_get_ega;     /* Set display capture fcn ptr  */
  557.  
  558.       break;
  559.  
  560.     case 0x0e:          /* 640 x 200 16-color EGA/VGA                   */
  561.  
  562.       max_width = min(width, 640);      /* Maximum image width          */
  563.       max_height = min(height, 200);    /* Maximum image height         */
  564.  
  565.       hdrp->bppixel = 1;                /* Bits per pixel               */
  566.       hdrp->horz_res = 640;             /* Horizontal resolution        */
  567.       hdrp->vert_res = 200;             /* Vertical resolution          */
  568.       hdrp->nplanes = 4;                /* Number of color planes       */
  569.  
  570.       /* Maximum four display pages supported                           */
  571.  
  572.       wbp->page_offset = 0x04000000L * (unsigned long) page;
  573.  
  574.       /* Calculate number of bytes to copy                              */
  575.  
  576.       wbp->num_bytes = (max_width + 7) >> 3;
  577.  
  578.       shift = (max_width & 7);  /* Calculate mask shift value           */
  579.  
  580.       wbp->pcx_funcp = pcx_get_ega;     /* Set display capture fcn ptr  */
  581.  
  582.       break;
  583.  
  584.     case 0x0f:          /* 640 x 350 2-color EGA/VGA                    */
  585.  
  586.       max_width = min(width, 640);      /* Maximum image width          */
  587.       max_height = min(height, 350);    /* Maximum image height         */
  588.  
  589.       hdrp->bppixel = 1;                /* Bits per pixel               */
  590.       hdrp->horz_res = 640;             /* Horizontal resolution        */
  591.       hdrp->vert_res = 350;             /* Vertical resolution          */
  592.       hdrp->nplanes = 2;                /* Number of color planes       */
  593.  
  594.       /* Maximum two display pages supported                            */
  595.  
  596.       wbp->page_offset = 0x08000000L * (unsigned long) page;
  597.  
  598.       /* Calculate number of bytes to copy                              */
  599.  
  600.       wbp->num_bytes = (max_width + 7) >> 3;
  601.  
  602.       shift = (max_width & 7);  /* Calculate mask shift value           */
  603.  
  604.       wbp->pcx_funcp = pcx_get_ega;     /* Set display capture fcn ptr  */
  605.  
  606.       break;
  607.  
  608.     case 0x10:          /* 640 x 350 16-color EGA/VGA                   */
  609.  
  610.       max_width = min(width, 640);      /* Maximum image width          */
  611.       max_height = min(height, 350);    /* Maximum image height         */
  612.  
  613.       hdrp->bppixel = 1;                /* Bits per pixel               */
  614.       hdrp->horz_res = 640;             /* Horizontal resolution        */
  615.       hdrp->vert_res = 350;             /* Vertical resolution          */
  616.       hdrp->nplanes = 4;                /* Number of color planes       */
  617.  
  618.       /* Maximum two display pages supported                            */
  619.  
  620.       wbp->page_offset = 0x08000000L * (unsigned long) page;
  621.  
  622.       /* Calculate number of bytes to copy                              */
  623.  
  624.       wbp->num_bytes = (max_width + 7) >> 3;
  625.  
  626.       shift = (max_width & 7);  /* Calculate mask shift value           */
  627.  
  628.       wbp->pcx_funcp = pcx_get_ega;     /* Set display capture fcn ptr  */
  629.  
  630.       break;
  631.  
  632.     case 0x11:          /* 640 x 480 2-color VGA                        */
  633.  
  634.       max_width = min(width, 640);      /* Maximum image width          */
  635.       max_height = min(height, 480);    /* Maximum image height         */
  636.  
  637.       hdrp->bppixel = 1;                /* Bits per pixel               */
  638.       hdrp->horz_res = 640;             /* Horizontal resolution        */
  639.       hdrp->vert_res = 480;             /* Vertical resolution          */
  640.       hdrp->nplanes = 1;                /* Number of color planes       */
  641.  
  642.       /* Calculate number of bytes to copy                              */
  643.  
  644.       wbp->num_bytes = (max_width + 7) >> 3;
  645.  
  646.       shift = (max_width & 7);  /* Calculate mask shift value           */
  647.  
  648.       wbp->pcx_funcp = pcx_get_ega;     /* Set display capture fcn ptr  */
  649.  
  650.       break;
  651.  
  652.     case 0x12:          /* 640 x 480 16-color VGA                       */
  653.  
  654.       max_width = min(width, 640);      /* Maximum image width          */
  655.       max_height = min(height, 480);    /* Maximum image height         */
  656.  
  657.       hdrp->bppixel = 1;                /* Bits per pixel               */
  658.       hdrp->horz_res = 640;             /* Horizontal resolution        */
  659.       hdrp->vert_res = 480;             /* Vertical resolution          */
  660.       hdrp->nplanes = 4;                /* Number of color planes       */
  661.  
  662.       /* Calculate number of bytes to copy                              */
  663.  
  664.       wbp->num_bytes = (max_width + 7) >> 3;
  665.  
  666.       shift = (max_width & 7);  /* Calculate mask shift value           */
  667.  
  668.       wbp->pcx_funcp = pcx_get_ega;     /* Set display capture fcn ptr  */
  669.  
  670.       break;
  671.  
  672.     case 0x13:          /* 320 x 200 256-color VGA                      */
  673.  
  674.       max_width = min(width, 320);      /* Maximum image width          */
  675.       max_height = min(height, 200);    /* Maximum image height         */
  676.  
  677.       hdrp->bppixel = 8;                /* Bits per pixel               */
  678.       hdrp->horz_res = 320;             /* Horizontal resolution        */
  679.       hdrp->vert_res = 200;             /* Vertical resolution          */
  680.       hdrp->nplanes = 1;                /* Number of color planes       */
  681.  
  682.       /* Calculate number of bytes to copy                              */
  683.  
  684.       wbp->num_bytes = max_width;
  685.  
  686.       shift = 0;        /* Dummy parameter                              */
  687.  
  688.       wbp->pcx_funcp = pcx_get_vga;     /* Set display capture fcn ptr  */
  689.  
  690.       break;
  691.  
  692.     default:            /* Other modes not supported                    */
  693.  
  694.       status = FALSE;
  695.  
  696.       break;
  697.   }
  698.  
  699.   /* Initialize common video mode-dependent parameters                  */
  700.  
  701.   hdrp->xlr = max_width - 1;            /* Lower right x-position       */
  702.   hdrp->ylr = max_height - 1;           /* Lower right y-position       */
  703.   hdrp->scrn_width = hdrp->horz_res;    /* Screen width                 */
  704.   hdrp->scrn_height = hdrp->vert_res;   /* Screen height                */
  705.  
  706.   /* Calculate mask for "white" data                                    */
  707.  
  708.   if (shift != 0)
  709.     wbp->mask = 0xff >> shift;
  710.   else
  711.     wbp->mask = 0x00;
  712.  
  713.   /* Initialize the file header palette                                 */
  714.  
  715.   status = pcx_init_palette(hdrp->palette, vmode);
  716.  
  717.   /* Calculate number of bytes per color plane scan line (must be an    */
  718.   /* even number of bytes)                                              */
  719.  
  720.   hdrp->bppscan = 2 * (((((hdrp->xlr * hdrp->bppixel) + 7) / 8) + 1) / 2);
  721.  
  722.   return (status);
  723. }
  724.  
  725. /*
  726.  *************************************************************************
  727.  *
  728.  *  PCX_INIT_PALETTE - Initialize File Header Palette
  729.  *
  730.  *  Purpose:    To initialize the file header 16-color palette.
  731.  *
  732.  *  Setup:      static BOOL pcx_init_palette
  733.  *              (
  734.  *                PCX_PAL *palettep,
  735.  *                int vmode
  736.  *              )
  737.  *
  738.  *  Where:      palettep is a pointer to the PCX file header buffer
  739.  *                "palette" member.
  740.  *              vmode is the MS-DOS video mode.  Valid values are:
  741.  *
  742.  *                0x04 -        320 x 200 4-color CGA
  743.  *                0x05 -        320 x 200 4-color CGA (color burst off)
  744.  *                0x06 -        640 x 200 2-color CGA
  745.  *                Ox07 -        720 x 348 Hercules monochrome
  746.  *                0x0d -        320 x 200 16-color EGA/VGA
  747.  *                0x0e -        640 x 200 16-color EGA/VGA
  748.  *                0x0f -        640 x 350 2-color EGA/VGA
  749.  *                0x10 -        640 x 350 16-color EGA/VGA
  750.  *                0x11 -        640 x 480 2-color VGA
  751.  *                0x12 -        640 x 480 16-color VGA
  752.  *                0x13 -        320 x 200 256-color VGA
  753.  *
  754.  *  Return:     TRUE if successful; otherwise FALSE.
  755.  *
  756.  *  Note:       The CGA color palette is not supported.
  757.  *
  758.  *              If a VGA display adapter is present, the color palette
  759.  *              registers can be read directly from the adapter using the
  760.  *              BIOS routine "Read All Palette Registers" (function 0x09).
  761.  *
  762.  *              Unfortunately, the EGA display adapter color palette
  763.  *              registers are write-only.  This means that the current
  764.  *              color palette for EGA displays cannot in general be read.
  765.  *
  766.  *              The BIOS routine "Set All Palette Registers" (function
  767.  *              0x02) will write the current palette register values to a
  768.  *              buffer called the Dynamic Save Area.  The EGA color
  769.  *              palette can be read from the first 16 bytes of this 256-
  770.  *              byte RAM block.
  771.  *
  772.  *              The Dynamic Save Area is not statically allocated; it must
  773.  *              be supplied by the user.  The BIOS video services data in
  774.  *              segment 0x40 includes a pointer at address 0040:00a8 that
  775.  *              references the Video Services Primary Pointer Table in the
  776.  *              EGA/VGA BIOS.  This table contains seven pointers, the
  777.  *              second of which is used by the "Set All Palette Registers"
  778.  *              routine to reference the Dynamic Save Area.  Since the
  779.  *              Dynamic Save Area does not exist at system initialization,
  780.  *              the value of this pointer is 0000:0000 (in which case the
  781.  *              the updated palette register values are not saved to RAM
  782.  *              when they are updated).
  783.  *
  784.  *              To utilize the EGA palette register save feature, the
  785.  *              user must perform the following:
  786.  *
  787.  *                1.  Save a copy of the pointer at address 0040:00a8.
  788.  *                2.  Allocate a buffer for a new Primary Pointer Table.
  789.  *                3.  Copy the existing Primary Pointer Table to the
  790.  *                    allocated buffer.
  791.  *                4.  Allocate a 256-byte buffer for a Dynamic Save Area.
  792.  *                5.  Initialize the second pointer of the Primary Pointer
  793.  *                    Table to point to the Dynamic Save Area buffer.
  794.  *
  795.  *              Before the program finishes, the user must also restore
  796.  *              the saved Primary Pointer Table pointer to address
  797.  *              0040:00a8.  Failure to do so will mean that subsequent
  798.  *              calls by other programs to the "Set All Palette
  799.  *              Registers" routine will result in the color palette
  800.  *              registers values being written to unallocated memory (or
  801.  *              memory that has been allocated for another purpose).
  802.  *
  803.  *              The function "pcx_init_dsa" performs the five steps
  804.  *              outlined above, while the function "pcx_free_dsa" restores
  805.  *              the saved pointer on completion of your program.
  806.  *
  807.  *              If the Dynamic Save Area pointer is 0000:0000 (the default
  808.  *              value at system initialization), the BIOS default color
  809.  *              palette settings for the appropriate mode are stored in
  810.  *              the file header color palette.
  811.  *
  812.  *************************************************************************
  813.  */
  814.  
  815. static BOOL pcx_init_palette
  816. (
  817.   PCX_PAL *palettep,
  818.   int vmode
  819. )
  820. {
  821.   int i;                        /* Scratch counter                      */
  822.   int val;                      /* Current palette register value       */
  823.   int red;                      /* Temporary value                      */
  824.   int green;                    /* Temporary value                      */
  825.   int blue;                     /* Temporary value                      */
  826.   unsigned char _far *ega_palp; /* EGA/VGA palette buffer pointer       */
  827.   unsigned char _far *dsap;     /* Dynamic Save Area pointer            */
  828.   union REGS regs;              /* 80x86 register values                */
  829.   struct SREGS sregs;           /* 80x86 segment register values        */
  830.  
  831.   if (vmode < 0x0d || vmode > 0x12)
  832.   {
  833.     /* Clear the file header palette                                    */
  834.  
  835.     memset(palettep, 0, sizeof(PCX_PAL) * PCX_PAL_SIZE);
  836.  
  837.     return (TRUE);
  838.   }
  839.  
  840.   /* Allocate a 16-color (plus border color) EGA/VGA palette buffer     */
  841.  
  842.   if ((ega_palp = (unsigned char _far *)
  843.       _fmalloc(sizeof(unsigned char) * (PCX_PAL_SIZE + 1))) ==
  844.       (unsigned char *) NULL)
  845.     return (FALSE);
  846.  
  847.   if (pcx_isvga() == TRUE)      /* Check for VGA display adapter        */
  848.   {
  849.     /* Read the EGA/VGA palette registers                               */
  850.  
  851.     regs.h.ah = 0x10;   /* Select "Read All Palette Registers" routine  */
  852.     regs.h.al = 0x09;
  853.  
  854.     /* Get the EGA palette buffer segment and offset values             */
  855.  
  856.     sregs.es =  *((unsigned int _far *) &ega_palp + 1);
  857.     regs.x.dx = *((unsigned int _far *) &ega_palp);
  858.  
  859.     int86x(0x10, ®s, ®s, &sregs);  /* Call BIOS video service     */
  860.   }
  861.   else
  862.   {
  863.     /* Check for a Dynamic Save Area buffer                             */
  864.  
  865.     dsap = *(*((unsigned char _far * _far * _far *) 0x004000a8L) + 1);
  866.  
  867.     if (dsap != (unsigned char _far *) NULL)
  868.     {
  869.       /* Copy the current palette into the local EGA/VGA palette buffer */
  870.  
  871.       (void) _fmemcpy(ega_palp, dsap, PCX_PAL_SIZE);
  872.     }
  873.     else
  874.     {
  875.       /* Copy the appropriate default palette settings                  */
  876.  
  877.       switch (vmode)
  878.       {
  879.         case 0x0d:      /* 320 x 200 16-color EGA                       */
  880.         case 0x0e:      /* 640 x 200 16-color EGA                       */
  881.  
  882.           _fmemcpy(ega_palp, pcx_EGA_DefPal_1, PCX_PAL_SIZE);
  883.  
  884.           break;
  885.  
  886.         case 0x0f:      /* 640 x 350 2-color EGA                        */
  887.  
  888.           _fmemcpy(ega_palp, pcx_EGA_DefPal_2, PCX_PAL_SIZE);
  889.  
  890.           break;
  891.  
  892.         case 0x10:      /* 640 x 350 16-color EGA                       */
  893.  
  894.           _fmemcpy(ega_palp, pcx_EGA_DefPal_3, PCX_PAL_SIZE);
  895.  
  896.           break;
  897.  
  898.         default:        /* (Should never reach here)                    */
  899.  
  900.           break;
  901.       }
  902.     }
  903.  
  904.     /* Map the EGA/VGA palette to the PCX file header palette           */
  905.  
  906.     for (i = 0; i < PCX_PAL_SIZE; i++)
  907.     {
  908.       val = (int) ega_palp[i];  /* Get current color palette value      */
  909.  
  910.       /* Extract color values                                           */
  911.  
  912.       red = ((val & 0x20) >> 5) | ((val & 0x04) >> 1);
  913.       green = ((val & 0x10) >> 4) | (val & 0x02);
  914.       blue = ((val & 0x08) >> 3) | ((val & 0x01) << 1);
  915.  
  916.       /* Map each color to a 6-bit value.  Only the top two bits are    */
  917.       /* significant for EGA displays.  The lower four bits (which      */
  918.       /* repeat the top two bits) are significant when the image is     */
  919.       /* presented on a VGA display emulating an EGA display.           */
  920.  
  921.       palettep[i].red = (BYTE) ((red << 6) | (red << 4) | (red << 2));
  922.       palettep[i].green = (BYTE) ((green << 6) | (green << 4) | (green <<
  923.           2));
  924.       palettep[i].blue = (BYTE) ((blue << 6) | (blue << 4) | (blue << 2));
  925.     }
  926.   }
  927.  
  928.   _ffree(ega_palp);     /* Free the EGA/VGA palette buffer              */
  929.  
  930.   return (TRUE);
  931. }
  932.  
  933. /*
  934.  *************************************************************************
  935.  *
  936.  *  PCX_WRITE_LINE - Write PCX Line
  937.  *
  938.  *  Purpose:    To write an image scan line to a PCX-format image file.
  939.  *
  940.  *  Setup:      static BOOL pcx_write_line
  941.  *              (
  942.  *                unsigned char *linep,
  943.  *                int buflen,
  944.  *                FILE *fp
  945.  *              )
  946.  *
  947.  *  Where:      linep is a PCX scan line buffer pointer.
  948.  *              buflen is the length of the image scan line buffer in
  949.  *                bytes.
  950.  *              fp is a file pointer.
  951.  *
  952.  *  Return:     TRUE if successful; otherwise FALSE.
  953.  *
  954.  *  Note:       The PCX scan line buffer is assumed to contain the color
  955.  *              plane scan lines in sequence, with padding for an even
  956.  *              number of bytes and trailing "white" data for each line as
  957.  *              appropriate.
  958.  *
  959.  *************************************************************************
  960.  */
  961.  
  962. static BOOL pcx_write_line
  963. (
  964.   unsigned char *linep,
  965.   int buflen,
  966.   FILE *fp
  967. )
  968. {
  969.   int curr_data;        /* Current data byte                            */
  970.   int prev_data;        /* Previous data byte                           */
  971.   int data_count;       /* Data repeat count                            */
  972.   int line_count;       /* Scan line byte count                         */
  973.  
  974.   prev_data = *linep++;         /* Initialize the previous data byte    */
  975.   data_count = 1;
  976.   line_count = 1;
  977.  
  978.   while (line_count < buflen)   /* Encode scan line                     */
  979.   {
  980.     curr_data = *linep++;       /* Get the current data byte            */
  981.     line_count++;               /* Increment the scan line counter      */
  982.  
  983.     if (curr_data == prev_data)         /* Repeating data bytes ?       */
  984.     {
  985.       data_count++;     /* Increment the data repeat count              */
  986.  
  987.       /* Check for maximum allowable repeat count                       */
  988.  
  989.       if (data_count == PCX_COMP_MASK)
  990.       {
  991.         /* Encode the data                                              */
  992.  
  993.         if (pcx_encode(prev_data, data_count, fp) == FALSE)
  994.           return (FALSE);
  995.  
  996.         data_count = 0;         /* Reset the data repeat count          */
  997.       }
  998.     }
  999.     else    /* End of repeating data bytes                              */
  1000.     {
  1001.       if (data_count > 0)
  1002.       {
  1003.         /* Encode the data                                              */
  1004.  
  1005.         if (pcx_encode(prev_data, data_count, fp) == FALSE)
  1006.           return (FALSE);
  1007.       }
  1008.  
  1009.       prev_data = curr_data;    /* Current data byte now previous       */
  1010.       data_count = 1;
  1011.     }
  1012.   }
  1013.  
  1014.   if (data_count > 0)   /* Any remaining data ?                         */
  1015.   {
  1016.     /* Encode the data                                                  */
  1017.  
  1018.     if (pcx_encode(prev_data, data_count, fp) == FALSE)
  1019.       return (FALSE);
  1020.   }
  1021.  
  1022.   return (TRUE);
  1023. }
  1024.  
  1025. /*
  1026.  *************************************************************************
  1027.  *
  1028.  *  PCX_ENCODE - Encode Byte Pair
  1029.  *
  1030.  *  Purpose:    To write an encoded byte pair (or a single unencoded
  1031.  *              byte) to a PCX-format image file.
  1032.  *
  1033.  *  Setup:      static BOOL pcx_encode
  1034.  *              (
  1035.  *                int data,
  1036.  *                int count,
  1037.  *                FILE *fp
  1038.  *              )
  1039.  *
  1040.  *  Where:      data is the data byte to be encoded (if necessary).
  1041.  *              count is the number of times the data byte is repeated in
  1042.  *                the image data.
  1043.  *              fp is a pointer to the PCX-format file the encoded byte
  1044.  *                pair or single byte is to be written to.
  1045.  *
  1046.  *  Return:     TRUE if successful; otherwise FALSE.
  1047.  *
  1048.  *************************************************************************
  1049.  */
  1050.  
  1051. static BOOL pcx_encode
  1052. (
  1053.   int data,
  1054.   int count,
  1055.   FILE *fp
  1056. )
  1057. {
  1058.   if (((data & PCX_COMP_FLAG) == PCX_COMP_FLAG) || count > 1)
  1059.   {
  1060.     /* Write the count byte                                             */
  1061.  
  1062.     if (putc(PCX_COMP_FLAG | count, fp) == EOF)
  1063.       return (FALSE);
  1064.   }
  1065.  
  1066.   /* Write the data byte                                                */
  1067.  
  1068.   if (putc(data, fp) == EOF)
  1069.     return (FALSE);
  1070.  
  1071.   return (TRUE);
  1072. }
  1073.  
  1074. /*
  1075.  *************************************************************************
  1076.  *
  1077.  *  PCX_WRITE_EXTPAL - Write Extended Palette
  1078.  *
  1079.  *  Purpose:    To read the current 256-color VGA palette and write an
  1080.  *              equivalent extended PCX palette to a PCX-format image
  1081.  *              file.
  1082.  *
  1083.  *  Setup:      static BOOL pcx_write_extpal
  1084.  *              (
  1085.  *                FILE *fp
  1086.  *              )
  1087.  *
  1088.  *  Where:      fp is a file pointer.
  1089.  *
  1090.  *  Return:     TRUE if successful; otherwise FALSE.
  1091.  *
  1092.  *************************************************************************
  1093.  */
  1094.  
  1095. static BOOL pcx_write_extpal
  1096. (
  1097.   FILE *fp
  1098. )
  1099. {
  1100.   int i;                        /* Scratch counter                      */
  1101.   BOOL status = TRUE;           /* Return status                        */
  1102.   PCX_PAL *palettep;            /* Extended PCX palette buffer pointer  */
  1103.   unsigned char _far *vga_palp; /* 256-color VGA palette buffer pointer */
  1104.   union REGS regs;              /* 80x86 register values                */
  1105.   struct SREGS sregs;           /* 80x86 segment register values        */
  1106.  
  1107.   /* Allocate an extended PCX palette buffer                            */
  1108.  
  1109.   if ((palettep = (PCX_PAL *) calloc(sizeof(PCX_PAL), PCX_EPAL_SIZE)) ==
  1110.       (PCX_PAL *) NULL)
  1111.     return (FALSE);
  1112.  
  1113.   /* Allocate a 256-color VGA palette buffer                            */
  1114.  
  1115.   if ((vga_palp = (unsigned char _far *) _fmalloc(sizeof(unsigned char) *
  1116.       768)) == (unsigned char *) NULL)
  1117.   {
  1118.     free(palettep);     /* Free the extended PCX palette buffer         */
  1119.     return (FALSE);
  1120.   }
  1121.  
  1122.   /* Read the current VGA palette (DAC registers)                       */
  1123.  
  1124.   regs.h.ah = 0x10;     /* Select "Read DAC Registers" BIOS routine     */
  1125.   regs.h.al = 0x17;
  1126.   regs.x.bx = 0;        /* Read all 256 DAC registers                   */
  1127.   regs.x.cx = 256;
  1128.   
  1129.   /* Get the VGA palette buffer segment and offset values               */
  1130.  
  1131.   sregs.es = *((unsigned int _far *) &vga_palp + 1);
  1132.   regs.x.dx = *((unsigned int _far *) &vga_palp);
  1133.  
  1134.   int86x(0x10, ®s, ®s, &sregs);   /* Call BIOS video service      */
  1135.  
  1136.   /* Map the VGA palette to an extended PCX palette                     */
  1137.  
  1138.   for (i = 0; i < PCX_EPAL_SIZE; i++)
  1139.   {
  1140.     palettep[i].red = (BYTE) (vga_palp[i * 3] << 2);
  1141.     palettep[i].green = (BYTE) (vga_palp[i * 3 + 1] << 2);
  1142.     palettep[i].blue = (BYTE) (vga_palp[i * 3 + 2] << 2);
  1143.   }
  1144.  
  1145.   /* Write the extended PCX palette indicator byte to the file          */
  1146.  
  1147.   if (status == TRUE)
  1148.     if (fputc(PCX_EPAL_FLAG, fp) == EOF)
  1149.       status = FALSE;
  1150.  
  1151.   /* Write the extended PCX palette to the file                         */
  1152.  
  1153.   if (status == TRUE)
  1154.     if (fwrite(palettep, sizeof(PCX_PAL), PCX_EPAL_SIZE, fp) !=
  1155.         PCX_EPAL_SIZE)
  1156.       status = FALSE;
  1157.  
  1158.   free(palettep);       /* Free the extended PCX palette buffer         */
  1159.  
  1160.   _ffree(vga_palp);     /* Free the VGA palette buffer                  */
  1161.  
  1162.   return (status);
  1163. }
  1164.  
  1165. /*
  1166.  *************************************************************************
  1167.  *
  1168.  *  PCX_GET_HERC - Get Hercules Scan Line
  1169.  *
  1170.  *  Purpose:    To read a Hercules monochrome graphics display adapter
  1171.  *              scan line into a buffer.
  1172.  *
  1173.  *  Setup:      static void pcx_get_herc
  1174.  *              (
  1175.  *                PCX_WORKBLK *wbp,
  1176.  *                unsigned char _far *linep,
  1177.  *                int line_num
  1178.  *              )
  1179.  *
  1180.  *  Where:      wbp is a PCX workblock pointer.
  1181.  *              linep is a pointer to where the scan line is to be
  1182.  *                returned.
  1183.  *              line_num is the scan line number.
  1184.  *
  1185.  *************************************************************************
  1186.  */
  1187.  
  1188. static void pcx_get_herc
  1189. (
  1190.   PCX_WORKBLK *wbp,
  1191.   unsigned char _far *linep,
  1192.   int line_num
  1193. )
  1194. {
  1195.   unsigned char _far *displayp;         /* Display buffer pointer       */
  1196.  
  1197.   /* Calculate Hercules display buffer pointer                          */
  1198.  
  1199.   displayp = (unsigned char _far *) (0xb0000000L + wbp->page_offset) +
  1200.       ((line_num >> 2) * 90) + 0x2000 * (line_num & 3);
  1201.  
  1202.   /* Copy data from the Hercules display buffer to the scan line buffer */
  1203.  
  1204.   (void) _fmemcpy(linep, displayp, wbp->num_bytes);
  1205.  
  1206.   /* Mask off unseen pixels                                             */
  1207.  
  1208.   linep[wbp->num_bytes - 1] |= wbp->mask;
  1209.  
  1210.   /* Pad scan line with "white" data byte (if necessary)                */
  1211.  
  1212.   if (wbp->num_bytes & 1)
  1213.     linep[wbp->num_bytes] = 0xff;
  1214. }
  1215.  
  1216. /*
  1217.  *************************************************************************
  1218.  *
  1219.  *  PCX_GET_CGA - Get CGA Scan Line
  1220.  *
  1221.  *  Purpose:    To read a CGA display adapter scan line into a buffer.
  1222.  *
  1223.  *  Setup:      static void pcx_get_cga
  1224.  *              (
  1225.  *                PCX_WORKBLK *wbp,
  1226.  *                unsigned char _far *linep,
  1227.  *                int line_num
  1228.  *              )
  1229.  *
  1230.  *  Where:      wbp is a PCX workblock pointer.
  1231.  *              linep is a pointer to where the scan line is to be
  1232.  *                returned.
  1233.  *              line_num is the scan line number.
  1234.  *
  1235.  *************************************************************************
  1236.  */
  1237.  
  1238. static void pcx_get_cga
  1239. (
  1240.   PCX_WORKBLK *wbp,
  1241.   unsigned char _far *linep,
  1242.   int line_num
  1243. )
  1244. {
  1245.   unsigned char _far *displayp;         /* Display buffer pointer       */
  1246.  
  1247.   /* Calculate CGA display buffer pointer                               */
  1248.  
  1249.   displayp = (unsigned char _far *) 0xb8000000L + ((line_num >> 1) * 80)
  1250.       + 0x2000 * (line_num & 1);
  1251.  
  1252.   /* Copy data from the CGA display buffer to the scan line buffer      */
  1253.  
  1254.   (void) _fmemcpy(linep, displayp, wbp->num_bytes);
  1255.  
  1256.   /* Mask off unseen pixels                                             */
  1257.  
  1258.   linep[wbp->num_bytes - 1] |= wbp->mask;
  1259.  
  1260.   /* Pad scan line with "white" data byte (if necessary)                */
  1261.  
  1262.   if (wbp->num_bytes & 1)
  1263.     linep[wbp->num_bytes] = 0xff;
  1264. }
  1265.  
  1266. /*
  1267.  *************************************************************************
  1268.  *
  1269.  *  PCX_GET_EGA - Get EGA/VGA Scan Line
  1270.  *
  1271.  *  Purpose:    To read an EGA/VGA display adapter scan line into a
  1272.  *              buffer.
  1273.  *
  1274.  *  Setup:      static void pcx_get_ega
  1275.  *              (
  1276.  *                PCX_WORKBLK *wbp,
  1277.  *                unsigned char _far *linep,
  1278.  *                int line_num
  1279.  *              )
  1280.  *
  1281.  *  Where:      wbp is a PCX workblock pointer.
  1282.  *              linep is a pointer to where the scan line is to be
  1283.  *                returned.
  1284.  *              line_num is the scan line number.
  1285.  *
  1286.  *************************************************************************
  1287.  */
  1288.  
  1289. static void pcx_get_ega
  1290. (
  1291.   PCX_WORKBLK *wbp,
  1292.   unsigned char _far *linep,
  1293.   int line_num
  1294. )
  1295. {
  1296.   int plane_num;                /* EGA/VGA color plane number           */
  1297.   unsigned char _far *displayp; /* Display buffer pointer               */
  1298.  
  1299.   /* Calculate buffer pointer                                           */
  1300.  
  1301.   displayp = (unsigned char _far *) (0xa0000000L + wbp->page_offset) +
  1302.       line_num * 80;
  1303.  
  1304.   /* Copy PCX scan line data from each color plane                      */
  1305.  
  1306.   for (plane_num = 0; plane_num < (int) wbp->header.nplanes; plane_num++)
  1307.   {
  1308.     /* Select the current color plane in EGA/VGA Read Mode 0            */
  1309.  
  1310.     outpw(0x03ce, (plane_num << 8) | 0x04);
  1311.  
  1312.     /* Copy data from the EGA/VGA display to the scan line buffer       */
  1313.  
  1314.     (void) _fmemcpy(linep, displayp, wbp->num_bytes);
  1315.  
  1316.     /* Mask off unseen pixels                                           */
  1317.  
  1318.     linep[wbp->num_bytes - 1] |= wbp->mask;
  1319.  
  1320.     /* Pad plane scan line with "white" data byte (if necessary)        */
  1321.  
  1322.     if (wbp->num_bytes & 1)
  1323.       linep[wbp->num_bytes] = 0xff;
  1324.  
  1325.     linep += wbp->header.bppscan;       /* Increment plane offset       */
  1326.   }
  1327.  
  1328.   /* Select EGA/VGA Write Mode 0 with all color planes enabled          */
  1329.  
  1330.   outpw(0x03c4, 0x0f02);
  1331. }
  1332.  
  1333. /*
  1334.  *************************************************************************
  1335.  *
  1336.  *  PCX_GET_VGA - Get VGA Scan Line
  1337.  *
  1338.  *  Purpose:    To read a VGA display adapter scan line into a buffer.
  1339.  *
  1340.  *  Setup:      static void pcx_get_vga
  1341.  *              (
  1342.  *                PCX_WORKBLK *wbp,
  1343.  *                unsigned char _far *linep,
  1344.  *                int line_num
  1345.  *              )
  1346.  *
  1347.  *  Where:      wbp is a PCX workblock pointer.
  1348.  *              linep is a pointer to where the scan line is to be
  1349.  *                returned.
  1350.  *              line_num is the scan line number.
  1351.  *
  1352.  *************************************************************************
  1353.  */
  1354.  
  1355. static void pcx_get_vga
  1356. (
  1357.   PCX_WORKBLK *wbp,
  1358.   unsigned char _far *linep,
  1359.   int line_num
  1360. )
  1361. {
  1362.   unsigned char _far *displayp;         /* Display buffer pointer       */
  1363.  
  1364.   /* Calculate buffer pointer                                           */
  1365.  
  1366.   displayp = (unsigned char _far *) 0xa0000000L + line_num * 320;
  1367.  
  1368.   /* Copy data from the VGA display buffer to the scan line buffer      */
  1369.  
  1370.   (void) _fmemcpy(linep, displayp, wbp->num_bytes);
  1371.  
  1372.   /* Pad scan line with "white" data byte (if necessary)                */
  1373.  
  1374.   if (wbp->num_bytes & 1)
  1375.     linep[wbp->num_bytes] = 0xff;
  1376. }
  1377.  
  1378.