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