]> 4ch.mooo.com Git - 16.git/blob - 16/PCX_LIB/PCX_DISP.C
code miraculously works on real hardware
[16.git] / 16 / PCX_LIB / PCX_DISP.C
1 /*\r
2  *************************************************************************\r
3  *\r
4  *  PCX_DISP.C - PCX_LIB Library Image Display 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  *          _fmemcpy            - "memcpy" for small model / far data\r
39  *          int86               - execute 80x86 interrupt routine\r
40  *          int86x              - execute 80x86 interrupt routine (far\r
41  *                                data)\r
42  *          _remapallpalette    - remap entire video display color palette\r
43  *          _selectpalette      - select CGA color palette\r
44  *          outpw               - output word to 80x86 I/O port\r
45  *          segread             - get current 80x86 segment register\r
46  *                                values\r
47  *\r
48  *  2.  When porting this program to other processors, remember that words\r
49  *      are stored by 80x86-based machines in the big-endian format.  That\r
50  *      is, the eight least significant bits (lower byte) are stored\r
51  *      first, followed by the eight most significant bits (upper byte).\r
52  *      If PCX-format files are transferred to little-endian machines\r
53  *      (such as those based on 680x0 and Z8000 processors), the order of\r
54  *      bytes within each word will have to be reversed before they can \r
55  *      be interpreted.  (This applies to the file header only, since the\r
56  *      encoded image data and optional 256-color palette are stored as\r
57  *      bytes.)\r
58  *\r
59  * 3.   MS-DOS does not recognize the 720 x 348 graphics mode of the\r
60  *      Hercules monochrome display adapter.  Therefore, the constant\r
61  *      PCX_HERC should never be passed as a video mode parameter to any\r
62  *      BIOS service routine.\r
63  *\r
64  *      The Microsoft C compiler includes a "video mode" parameter\r
65  *      definition (_HERCMONO) that is defined as 0x08.  This is a\r
66  *      reserved MS-DOS video mode that is apparently used internally by\r
67  *      the ROM BIOS.  It can, however, be passed to the Microsoft C\r
68  *      library function "_setvideomode" to force the Hercules display\r
69  *      adapter into graphics mode.\r
70  *\r
71  *      Most other MS-DOS C compilers offer similar library functions to\r
72  *      force the Hercules monochrome display adapter into its 720 x 348\r
73  *      graphics mode.\r
74  *\r
75  ************************************************************************* \r
76  */\r
77 \f\r
78 /*      INCLUDE FILES                                                   */\r
79 \r
80 #include <stdio.h>\r
81 #include <stdlib.h>\r
82 #include <string.h>\r
83 #include <conio.h>\r
84 #include <dos.h>\r
85 #include <malloc.h>\r
86 #include <graph.h>\r
87 #include "pcx_int.h"\r
88 \f\r
89 /*      FORWARD REFERENCES                                              */\r
90 \r
91 static BOOL pcx_read_init(PCX_WORKBLK *, int, int);\r
92 static BOOL pcx_read_extpal(PCX_WORKBLK *);\r
93 static BOOL pcx_read_header(PCX_WORKBLK *);\r
94 static BOOL pcx_read_line(PCX_WORKBLK *, unsigned char *, int);\r
95 static BOOL pcx_set_palette(PCX_PAL *, int);\r
96 \r
97 static void pcx_cga_palette(PCX_PAL *, int);\r
98 static void pcx_put_cga(PCX_WORKBLK *, unsigned char _far *, int);\r
99 static void pcx_put_ega(PCX_WORKBLK *, unsigned char _far *, int);\r
100 static void pcx_put_herc(PCX_WORKBLK *, unsigned char _far *, int);\r
101 static void pcx_put_vga(PCX_WORKBLK *, unsigned char _far *, int);\r
102 \f\r
103 /*      GLOBALS                                                         */\r
104 \f\r
105 /*      PUBLIC FUNCTIONS                                                */\r
106 \r
107 /*\r
108  *************************************************************************\r
109  *\r
110  *  PCX_READ - Read PCX Image File\r
111  *\r
112  *  Purpose:    To read and display a PCX-format image file.\r
113  *\r
114  *  Setup:      BOOL pcx_read\r
115  *              (\r
116  *                char *fname,\r
117  *                int vmode,\r
118  *                int page\r
119  *              )\r
120  *\r
121  *  Where:      fname is a PCX image file name.\r
122  *              vmode is the MS-DOS video mode.  Valid values are:\r
123  *\r
124  *                PCX_HERC -    720 x 348 Hercules monochrome\r
125  *                0x04 -        320 x 200 4-color CGA\r
126  *                0x05 -        320 x 200 4-color CGA (color burst off)\r
127  *                0x06 -        640 x 200 2-color CGA\r
128  *                0x0d -        320 x 200 16-color EGA/VGA\r
129  *                0x0e -        640 x 200 16-color EGA/VGA\r
130  *                0x0f -        640 x 350 2-color EGA/VGA\r
131  *                0x10 -        640 x 350 16-color EGA/VGA\r
132  *                0x11 -        640 x 480 2-color VGA\r
133  *                0x12 -        640 x 480 16-color VGA\r
134  *                0x13 -        320 x 200 256-color VGA\r
135  *\r
136  *              page is the video display page number.  Valid values are:\r
137  *\r
138  *                Mode PCX_HERC - 0 or 1\r
139  *                Mode 0x0d     - 0 to 7\r
140  *                Mode 0x0e     - 0 to 3\r
141  *                Mode 0x0f     - 0 or 1\r
142  *                Mode 0x10     - 0 or 1\r
143  *                All Other     - 0\r
144  *\r
145  *  Return:     TRUE if successful; otherwise FALSE.\r
146  *\r
147  *  Note:       The video display adapter must be in the appropriate mode\r
148  *              and active page for the image to be displayed.\r
149  *\r
150  *************************************************************************\r
151  */\r
152 \r
153 BOOL pcx_read\r
154 (\r
155   char *fname,\r
156   int vmode,\r
157   int page\r
158 )\r
159 {\r
160   int bpline;                   /* Number of bytes per scan line        */\r
161   int line_num;                 /* Scan line number                     */\r
162   int max_lines;                /* Maximum number of scan lines         */\r
163   unsigned char *linep;         /* PCX scan line buffer pointer         */\r
164   BOOL status = TRUE;           /* Return status                        */\r
165   PCX_WORKBLK *wbp;             /* PCX image file workblock pointer     */\r
166 \r
167   /* Open a PCX image file workblock                                    */\r
168 \r
169   if ((wbp = pcx_open(fname, FALSE)) == (PCX_WORKBLK *) NULL)\r
170     return (FALSE);\r
171 \r
172   /* Initialize the workblock for reading                               */\r
173 \r
174   if (pcx_read_init(wbp, vmode, page) == FALSE)\r
175   {\r
176     (void) pcx_close(wbp);      /* Close the PCX workblock              */\r
177     return (FALSE);\r
178   }\r
179 \r
180   /* Calculate the image height                                         */\r
181 \r
182   max_lines = wbp->header.yul + wbp->header.ylr + 1;\r
183 \r
184   /* Calculate number of bytes per line (for all color planes)          */\r
185 \r
186   bpline = wbp->header.bppscan * wbp->header.nplanes;\r
187 \r
188   /* Allocate the PCX scan line buffer                                  */\r
189 \r
190   if ((linep = (unsigned char *) malloc(bpline)) != (unsigned char *)\r
191       NULL)\r
192   {\r
193     /* Set the file pointer to the beginning of the encoded image data  */\r
194 \r
195     if (status == TRUE)\r
196       if (fseek(wbp->fp, (long) (sizeof(PCX_HDR)), SEEK_SET) != 0)\r
197         status = FALSE;\r
198 \r
199     /* Set the video display adapter color palette unless the PCX file  */\r
200     /* is Version 3.0 (i.e. - PC Paintbrush Version 2.8 w/o palette)    */\r
201 \r
202     if (status == TRUE)\r
203       if (wbp->header.version != 3)\r
204         if (pcx_set_palette(wbp->palettep, vmode) == FALSE)\r
205           status = FALSE;\r
206 \r
207     /* Read the image line by line                                      */\r
208 \r
209     if (status == TRUE)\r
210     {\r
211       for (line_num = 0; line_num < max_lines; line_num++)\r
212       {\r
213         /* Read the current scan line                                   */\r
214 \r
215         if ((status = pcx_read_line(wbp, linep, bpline)) == FALSE)\r
216         {\r
217           status = FALSE;\r
218           break;\r
219         }\r
220 \r
221         /* Display the current scan line                                */\r
222 \r
223         wbp->pcx_funcp(wbp, (unsigned char _far *) linep, line_num);\r
224       }\r
225     }\r
226 \r
227     free(linep);        /* Free the PCX scan line buffer                */\r
228   }\r
229   else\r
230     status = FALSE;\r
231                          \r
232   if (pcx_close(wbp) == FALSE)  /* Close the PCX workblock              */\r
233     status = FALSE;\r
234 \r
235   return (status);\r
236 }\r
237 \f\r
238 /*      PRIVATE FUNCTIONS                                               */\r
239 \r
240 /*\r
241  *************************************************************************\r
242  *\r
243  *  PCX_READ_INIT - Initialize PCX Workblock For Reading\r
244  *\r
245  *  Purpose:    To initialize a PCX image file workblock for reading.\r
246  *\r
247  *  Setup:      static BOOL pcx_read_init\r
248  *              (\r
249  *                PCX_WORKBLK *wbp,\r
250  *                int vmode,\r
251  *                int page\r
252  *              )\r
253  *\r
254  *  Where:      wbp is a PCX workblock pointer.\r
255  *              vmode is the MS-DOS video mode.  Valid values are:\r
256  *\r
257  *                PCX_HERC -    720 x 348 Hercules monochrome\r
258  *                0x04 -        320 x 200 4-color CGA\r
259  *                0x05 -        320 x 200 4-color CGA (color burst off)\r
260  *                0x06 -        640 x 200 2-color CGA\r
261  *                0x0d -        320 x 200 16-color EGA/VGA\r
262  *                0x0e -        640 x 200 16-color EGA/VGA\r
263  *                0x0f -        640 x 350 2-color EGA/VGA\r
264  *                0x10 -        640 x 350 16-color EGA/VGA\r
265  *                0x11 -        640 x 480 2-color VGA\r
266  *                0x12 -        640 x 480 16-color VGA\r
267  *                0x13 -        320 x 200 256-color VGA\r
268  *\r
269  *              page is the video display page number.  Valid values are:\r
270  *\r
271  *                Mode PCX_HERC - 0 or 1\r
272  *                Mode 0x0d     - 0 to 7\r
273  *                Mode 0x0e     - 0 to 3\r
274  *                Mode 0x0f     - 0 or 1\r
275  *                Mode 0x10     - 0 or 1\r
276  *                All Other      - 0\r
277  *\r
278  *  Return:     TRUE if successful; otherwise FALSE.\r
279  *\r
280  *************************************************************************\r
281  */\r
282 \r
283 static BOOL pcx_read_init\r
284 (\r
285   PCX_WORKBLK *wbp,\r
286   int vmode,\r
287   int page\r
288 )\r
289 {\r
290   int width;                    /* Display width                        */\r
291   int leftover;                 /* Number of unseen bits                */\r
292   BOOL status = TRUE;           /* Return status                        */\r
293 \r
294   /* Read the file header                                               */\r
295 \r
296   if ((pcx_read_header(wbp)) == FALSE)\r
297     return (FALSE);\r
298 \r
299   /* Initialize the workblock color palette pointer                     */\r
300 \r
301   wbp->palettep = wbp->header.palette;\r
302   wbp->epal_flag = FALSE;\r
303 \r
304   /* Read the extended palette (if any)                                 */\r
305 \r
306   if (vmode == 0x13 && wbp->header.version == 5)\r
307     if (pcx_read_extpal(wbp) == FALSE)\r
308       return (FALSE);\r
309 \r
310   /* Initialize the display page address offset                         */\r
311 \r
312   wbp->page_offset = (unsigned long) 0L;\r
313 \r
314   switch (vmode)        /* Select PCX line display function             */\r
315   {\r
316     case PCX_HERC:      /* 720 x 348 Hercules monochrome                */\r
317 \r
318       /* Hercules monochrome display adapter supports 2 pages           */\r
319 \r
320       wbp->page_offset = 0x08000000L * (unsigned long) page;\r
321 \r
322       /* Calculate display width in pixels                              */\r
323 \r
324       width = min((wbp->header.xlr - wbp->header.xul + 1), 720);\r
325 \r
326       /* Calculate number of bytes to display                           */\r
327 \r
328       wbp->num_bytes = (width + 7) >> 3;\r
329 \r
330       /* Calculate mask for leftover bits                               */\r
331 \r
332       if ((leftover = width & 7) != 0)\r
333         wbp->mask = (0xff << (8 - leftover)) & 0xff;\r
334       else\r
335         wbp->mask = 0xff;\r
336 \r
337       wbp->pcx_funcp = pcx_put_herc;    /* Set the display function ptr */\r
338 \r
339       break;\r
340 \r
341     case 0x04:          /* 320 x 200 4-color CGA                        */\r
342     case 0x05:          /* 320 x 200 4-color CGA (color burst off)      */\r
343   \r
344       /* Calculate display width in pixels                              */\r
345 \r
346       width = min((wbp->header.xlr - wbp->header.xul + 1), 320);\r
347 \r
348       /* Calculate number of bytes to display                           */\r
349 \r
350       wbp->num_bytes = (width + 3) >> 2;\r
351 \r
352       /* Calculate mask for leftover bits                               */\r
353 \r
354       if ((leftover = (width & 3) << 1) != 0)\r
355         wbp->mask = (0xff << (8 - leftover)) & 0xff;\r
356       else\r
357         wbp->mask = 0xff;\r
358 \r
359       wbp->pcx_funcp = pcx_put_cga;     /* Set the display function ptr */\r
360 \r
361       break;\r
362 \r
363     case 0x06:          /* 640 x 200 2-color CGA                        */\r
364 \r
365       /* Calculate display width in pixels                              */\r
366 \r
367       width = min((wbp->header.xlr - wbp->header.xul + 1), 640);\r
368 \r
369       /* Calculate number of bytes to display                           */\r
370 \r
371       wbp->num_bytes = (width + 7) >> 3;\r
372 \r
373       /* Calculate mask for leftover bits                               */\r
374 \r
375       if ((leftover = width & 7) != 0)\r
376         wbp->mask = (0xff << (8 - leftover)) & 0xff;\r
377       else\r
378         wbp->mask = 0xff;\r
379 \r
380       wbp->pcx_funcp = pcx_put_cga;     /* Set the display function ptr */\r
381 \r
382       break;\r
383 \r
384     case 0x0d:          /* 320 x 200 16-color EGA/VGA                   */\r
385     case 0x0e:          /* 640 x 200 16-color EGA/VGA                   */\r
386     case 0x0f:          /* 640 x 350 2-color EGA/VGA                    */\r
387     case 0x10:          /* 640 x 350 16-color EGA/VGA                   */\r
388     case 0x11:          /* 640 x 480 2-color VGA                        */\r
389     case 0x12:          /* 640 x 480 16-color VGA                       */\r
390 \r
391       switch (vmode)    /* Initialize the display adapter page offset   */\r
392       {\r
393         case 0x0d:      /* 320 x 200 16-color EGA/VGA (8 pages maximum) */\r
394 \r
395           wbp->page_offset = 0x02000000L * (unsigned long) page;\r
396 \r
397           break;\r
398 \r
399         case 0x0e:      /* 640 x 200 16-color EGA/VGA (4 pages maximum) */\r
400 \r
401           wbp->page_offset = 0x04000000L * (unsigned long) page;\r
402 \r
403           break;\r
404 \r
405         case 0x0f:      /* 640 x 350 2-color EGA/VGA (2 pages maximum)  */\r
406         case 0x10:      /* 640 x 350 16-color EGA/VGA (2 pages maximum) */\r
407 \r
408           wbp->page_offset = 0x08000000L * (unsigned long) page;\r
409 \r
410           break;\r
411 \r
412         default:        /* All other modes support only one page        */\r
413 \r
414           break;\r
415       }\r
416 \r
417       /* Calculate display width in pixels                              */\r
418 \r
419       width = min((wbp->header.xlr - wbp->header.xul + 1), 640);\r
420 \r
421       /* Calculate number of bytes to display                           */\r
422 \r
423       wbp->num_bytes = (width + 7) >> 3;\r
424 \r
425       /* Calculate mask for leftover bits                               */\r
426 \r
427       if ((leftover = width & 7) != 0)\r
428         wbp->mask = (0xff << (8 - leftover)) & 0xff;\r
429       else\r
430         wbp->mask = 0xff;\r
431 \r
432       wbp->pcx_funcp = pcx_put_ega;     /* Set the display function ptr */\r
433 \r
434       break;\r
435 \r
436     case 0x13:          /* 320 x 200 256-color VGA                      */\r
437 \r
438       /* Calculate number of bytes to display                           */\r
439 \r
440       wbp->num_bytes = min((wbp->header.xlr - wbp->header.xul + 1), 320);\r
441 \r
442       wbp->mask = 0;  /* Dummy parameter                                */\r
443 \r
444       wbp->pcx_funcp = pcx_put_vga;     /* Set the display function ptr */\r
445 \r
446       break;\r
447 \r
448     default:            /* Other display adapters not supported         */\r
449 \r
450       status = FALSE;\r
451 \r
452       break;\r
453   }\r
454 \r
455   return (status);\r
456 }\r
457 \f\r
458 /*\r
459  *************************************************************************\r
460  *\r
461  *  PCX_READ_HEADER - Read PCX File Header\r
462  *\r
463  *  Purpose:    To read and validate a PCX file header.\r
464  *\r
465  *  Setup:      static BOOL pcx_read_header\r
466  *              (\r
467  *                PCX_WORKBLK *wbp\r
468  *              )\r
469  *\r
470  *  Where:      wbp is a PCX image file workblock pointer.\r
471  *\r
472  *  Return:     TRUE if successful; otherwise FALSE.\r
473  *\r
474  *  Result:     The file header is read into the "header" member of the\r
475  *              PCX workblock.\r
476  *\r
477  *************************************************************************\r
478  */\r
479 \r
480 static BOOL pcx_read_header\r
481 (\r
482   PCX_WORKBLK *wbp\r
483 )\r
484 {\r
485   BOOL status = TRUE;   /* Status flag                                  */\r
486   PCX_HDR *hdrp;        /* PCX file header buffer pointer               */\r
487 \r
488   hdrp = &(wbp->header);        /* Initialize the file header pointer   */\r
489 \r
490   /* Read the file header                                               */\r
491 \r
492   if (fseek(wbp->fp, 0L, SEEK_SET) != 0)\r
493     status = FALSE;\r
494 \r
495   if (status == TRUE)\r
496     if (fread(hdrp, sizeof(PCX_HDR), 1, wbp->fp) != 1)\r
497       status = FALSE;\r
498 \r
499   /* Validate the PCX file format                                       */\r
500 \r
501   if (status == TRUE)\r
502     if ((hdrp->pcx_id != 0x0a) || (hdrp->encoding != 1))\r
503       status = FALSE;\r
504 \r
505   return (status);\r
506 }\r
507 \f\r
508 /*\r
509  *************************************************************************\r
510  *\r
511  *  PCX_READ_EXTPAL - Read Extended Palette\r
512  *\r
513  *  Purpose:    To read an extended (256-color) palette (if it exists).\r
514  *\r
515  *  Setup:      static BOOL pcx_read_extpal\r
516  *              (\r
517  *                PCX_WORKBLK *wbp\r
518  *              )\r
519  *\r
520  *  Where:      wbp is a PCX image file workblock pointer.\r
521  *\r
522  *  Return:     TRUE if successful; otherwise FALSE.\r
523  *\r
524  *  Note:       It is possible for a PCX image file without an appended\r
525  *              256-color palette to have the value 0x0c as the 769th byte\r
526  *              (the location of the extended palette indicator byte) from \r
527  *              the end of the file (i.e. - in the encoded image data \r
528  *              section).  This function will misinterpret the following\r
529  *              768 bytes of encoded image data as an extended palette.\r
530  *\r
531  *              This problem will only occur if an attempt is made to\r
532  *              display a PCX image using the wrong MS-DOS video mode.  It\r
533  *              can be detected by decoding the image data and using \r
534  *              "ftell" to note the file position of the end of the \r
535  *              encoded image data section, then comparing it to the file\r
536  *              position of the indicator byte.  If the supposed indicator\r
537  *              byte is located within the encoded image data section, the\r
538  *              indicator byte is invalid and so the file header palette\r
539  *              should be used instead.\r
540  *\r
541  *************************************************************************\r
542  */\r
543 \r
544 static BOOL pcx_read_extpal\r
545 (\r
546   PCX_WORKBLK *wbp\r
547 )\r
548 {\r
549   int indicator;        /* PCX extended palette indicator               */\r
550 \r
551   /* Position the file pointer to the extended palette indicator byte   */\r
552 \r
553   if (fseek(wbp->fp, -769L, SEEK_END) != 0)\r
554     return (FALSE);\r
555 \r
556   /* Read the (assumed) extended palette indicator byte                 */\r
557 \r
558   if ((indicator = getc(wbp->fp)) == EOF)\r
559     return (FALSE);\r
560 \r
561   if (indicator == PCX_EPAL_FLAG)       /* Check for indicator byte     */\r
562   {\r
563     /* Allocate an extended palette buffer                              */\r
564 \r
565     if ((wbp->palettep = (PCX_PAL *) calloc(sizeof(PCX_PAL),\r
566         PCX_EPAL_SIZE)) == (PCX_PAL *) NULL)\r
567       return (FALSE);\r
568 \r
569     /* Read the extended palette                                        */\r
570 \r
571     if (fread(wbp->palettep, sizeof(PCX_PAL), PCX_EPAL_SIZE, wbp->fp) !=\r
572         PCX_EPAL_SIZE)\r
573     {\r
574       free(wbp->palettep);      /* Free the extended palette buffer     */\r
575       return (FALSE);\r
576     }\r
577 \r
578     wbp->epal_flag = TRUE;      /* Indicate extended palette present    */\r
579   }\r
580 \r
581   return (TRUE);\r
582 }\r
583 \f\r
584 /*\r
585  *************************************************************************\r
586  *\r
587  *  PCX_READ_LINE - Read PCX Line\r
588  *\r
589  *  Purpose:    To read an encoded line (all color planes) from a PCX-\r
590  *              format image file and write the decoded data to a line\r
591  *              buffer.\r
592  *\r
593  *  Setup:      static BOOL pcx_read_line\r
594  *              (\r
595  *                PCX_WORKBLK *wbp,\r
596  *                unsigned char *linep,\r
597  *                int bpline\r
598  *              )\r
599  *\r
600  *  Where:      wbp is a PCX image file workblock pointer.\r
601  *              linep is a PCX scan line buffer pointer.\r
602  *              bpline is the number of bytes per scan line (all color\r
603  *                planes).\r
604  *\r
605  *  Return:     TRUE if successful; otherwise FALSE.\r
606  *\r
607  *************************************************************************\r
608  */\r
609 \r
610 static BOOL pcx_read_line\r
611 (\r
612   PCX_WORKBLK *wbp,\r
613   unsigned char *linep,\r
614   int bpline\r
615 )\r
616 {\r
617   int data;             /* Image data byte                              */\r
618   int count;            /* Image data byte repeat count                 */\r
619   int offset = 0;       /* Scan line buffer offset                      */\r
620 \r
621   while (offset < bpline)       /* Decode current scan line             */\r
622   {\r
623     if ((data = getc(wbp->fp)) == EOF)  /* Get next byte                */\r
624       return (FALSE);\r
625 \r
626     /* If top two bits of byte are set, lower six bits show how         */\r
627     /* many times to duplicate next byte                                */\r
628 \r
629     if ((data & PCX_COMP_FLAG) == PCX_COMP_FLAG)\r
630     {\r
631       count = data & PCX_COMP_MASK;     /* Mask off repeat count        */\r
632 \r
633       if ((data = getc(wbp->fp)) == EOF)        /* Get next byte        */\r
634         return (FALSE);\r
635 \r
636       memset(linep, data, count);       /* Duplicate byte               */\r
637       linep += count;\r
638       offset += count;\r
639     }\r
640     else\r
641     {\r
642       *linep++ = (unsigned char) data;  /* Copy byte                    */\r
643       offset++;\r
644     }\r
645   }\r
646 \r
647   return (TRUE);\r
648 }\r
649 \f\r
650 /*\r
651  *************************************************************************\r
652  *\r
653  *  PCX_SET_PALETTE - Set Palette\r
654  *\r
655  *  Purpose:    To set the display palette according to a PCX file\r
656  *              palette.\r
657  *\r
658  *  Setup:      static BOOL pcx_set_palette\r
659  *              (\r
660  *                PCX_PAL *palettep,\r
661  *                int vmode\r
662  *              )\r
663  *\r
664  *  Where:      palettep is a pointer to a PCX file palette.\r
665  *              vmode is the MS-DOS video mode.  Valid values are:\r
666  *\r
667  *                PCX_HERC -    720 x 348 Hercules monochrome\r
668  *                0x04 -        320 x 200 4-color CGA\r
669  *                0x05 -        320 x 200 4-color CGA (color burst off)\r
670  *                0x06 -        640 x 200 2-color CGA\r
671  *                0x0d -        320 x 200 16-color EGA/VGA\r
672  *                0x0e -        640 x 200 16-color EGA/VGA\r
673  *                0x0f -        640 x 350 2-color EGA/VGA\r
674  *                0x10 -        640 x 350 16-color EGA/VGA\r
675  *                0x11 -        640 x 480 2-color VGA\r
676  *                0x12 -        640 x 480 16-color VGA\r
677  *                0x13 -        320 x 200 256-color VGA\r
678  *\r
679  *  Return:     TRUE if successful; otherwise FALSE.\r
680  *\r
681  *************************************************************************\r
682  */\r
683 \r
684 static BOOL pcx_set_palette\r
685 (\r
686   PCX_PAL *palettep,\r
687   int vmode\r
688 )\r
689 {\r
690   int i;                        /* Scratch counter                      */\r
691   int red_lo;                   /* Low red intensity                    */\r
692   int red_hi;                   /* High red intensity                   */\r
693   int green_lo;                 /* Green low intensity                  */\r
694   int green_hi;                 /* Green high intensity                 */\r
695   int blue_lo;                  /* Blue low intensity                   */\r
696   int blue_hi;                  /* Blue high intensity                  */\r
697   unsigned char *ega_palp;      /* EGA 16-color palette buffer pointer  */\r
698   unsigned long *vga_palp;      /* VGA 256-color palette buffer pointer */\r
699   BOOL status = TRUE;           /* Return status                        */\r
700   union REGS regs;              /* 80x86 register values                */\r
701   struct SREGS sregs;           /* 80x86 segment register values        */\r
702 \r
703   switch (vmode)\r
704   {\r
705     case PCX_HERC:      /* 720 x 348 Hercules monochrome                */\r
706 \r
707       break;\r
708 \r
709     case 0x04:          /* 320 x 200 4-color CGA display                */\r
710     case 0x05:          /* 320 x 200 monochrome CGA display (burst off) */\r
711     case 0x06:          /* 640 x 200 2-color CGA display                */\r
712 \r
713       /* Set the CGA color palette                                      */\r
714 \r
715       pcx_cga_palette(palettep, vmode);\r
716 \r
717       break;\r
718 \r
719     case 0x0d:          /* 320 x 200 16-color EGA/VGA                   */\r
720     case 0x0e:          /* 640 x 200 16-color EGA/VGA                   */\r
721     case 0x0f:          /* 640 x 350 2-color EGA/VGA                    */\r
722     case 0x10:          /* 640 x 350 16-color EGA/VGA                   */\r
723     case 0x11:          /* 640 x 480 2-color VGA                        */\r
724     case 0x12:          /* 640 x 480 16-color VGA                       */\r
725 \r
726       if (pcx_isvga() == TRUE)  /* Check for VGA display adapter        */\r
727       {\r
728         /* Allocate a 16-color VGA display adapter palette buffer       */\r
729 \r
730         if ((vga_palp = (unsigned long *) calloc(sizeof(unsigned long),\r
731             PCX_PAL_SIZE)) == (unsigned long *) NULL)\r
732         {\r
733           status = FALSE;\r
734           break;\r
735         }\r
736 \r
737         /* Map PCX hardware palette to 16-color VGA palette (each color */\r
738         /* value is a "long" with the form:                             */\r
739         /*                                                              */\r
740         /*      00000000-00BBBBBB-00GGGGGG-00RRRRRR                     */\r
741         /*                                                              */\r
742         /* where each color is a 6-bit value.                           */\r
743 \r
744         for (i = 0; i < PCX_PAL_SIZE; i++)\r
745           vga_palp[i] = (long) (palettep[i].red >> 2) |\r
746               ((long) (palettep[i].green >> 2)) << 8 |\r
747               ((long) (palettep[i].blue >> 2)) << 16;\r
748 \r
749         (void) _remapallpalette(vga_palp);      /* Remap entire palette */\r
750 \r
751         free(vga_palp);         /* Free the VGA palette buffer          */\r
752       }\r
753       else      /* EGA display adapter                                  */\r
754       {\r
755         /* Allocate an EGA display adapter palette buffer               */\r
756 \r
757         if ((ega_palp = (unsigned char *) calloc(sizeof(unsigned char),\r
758             PCX_PAL_SIZE + 1)) == (unsigned char *) NULL)\r
759         {\r
760           status = FALSE;\r
761           break;\r
762         }\r
763 \r
764         /* Map PCX hardware palette to 16-color EGA palette (each EGA   */\r
765         /* color value is an "unsigned char" with the form:             */\r
766         /*                                                              */\r
767         /*        0  0  R' G' B' R  G  B                                */\r
768         /*                                                              */\r
769         /* where X' is the low-intensity value and X is the high        */\r
770         /* intensity value for the color X.)                            */\r
771         /*                                                              */\r
772         /* NOTE: the "_remapallpalette" function could be used to set   */\r
773         /*       the palette for EGA display adapters.  However, this   */\r
774         /*       function does not appear to update the palette         */\r
775         /*       register values in the Dynamic Save Area (see the      */\r
776         /*       function header for "pcx_init_palette" in PCX_FILE.C)  */\r
777         /*       for a detailed explanation).                           */\r
778 \r
779         for (i = 0; i < PCX_PAL_SIZE; i++)\r
780         {\r
781           /* Extract low and high intensity bits for each color         */\r
782 \r
783           red_lo = (palettep[i].red >> 6) & 0x01;\r
784           red_hi = (palettep[i].red >> 6) & 0x02;\r
785           green_lo = (palettep[i].green >> 6) & 0x01;\r
786           green_hi = (palettep[i].green >> 6) & 0x02;\r
787           blue_lo = (palettep[i].blue >> 6) & 0x01;\r
788           blue_hi = (palettep[i].blue >> 6) & 0x02;\r
789 \r
790           /* Combine color intensity bits for EGA palette value         */\r
791 \r
792           ega_palp[i] = (unsigned char) ((red_lo << 5) | (green_lo << 4) |\r
793               (blue_lo << 3) | (red_hi << 1) | green_hi | (blue_hi >>\r
794               1));\r
795         }\r
796 \r
797         /* Set the border (overscan) color to black (BIOS default)      */\r
798 \r
799         ega_palp[16] = (unsigned char) 0;\r
800 \r
801         regs.h.ah = 0x10;       /* Select "Set All Palette Registers"   */\r
802         regs.h.al = 0x02;\r
803 \r
804         /* Get the EGA palette registers buffer offset value            */\r
805 \r
806         regs.x.dx = (unsigned int) ega_palp;\r
807 \r
808         segread(&sregs);  /* Get the current DS segment register value  */\r
809 \r
810         sregs.es = sregs.ds;\r
811 \r
812         int86x(0x10, &regs, &regs, &sregs);  /* Call BIOS video service */\r
813 \r
814         free(ega_palp);         /* Free the EGA palette buffer          */\r
815       }\r
816 \r
817       break;\r
818 \r
819     case 0x13:          /* 320 x 200 256-color VGA display              */\r
820 \r
821       /* Allocate a 256-color VGA display adapter palette buffer        */\r
822 \r
823       if ((vga_palp = (unsigned long *) calloc(sizeof(unsigned long),\r
824           PCX_EPAL_SIZE)) == (unsigned long *) NULL)\r
825       {\r
826         status = FALSE;\r
827         break;\r
828       }\r
829 \r
830       /* Map PCX extended palette to 256-color VGA palette              */\r
831 \r
832       for (i = 0; i < PCX_EPAL_SIZE; i++)\r
833         vga_palp[i] = (long) (palettep[i].red >> 2) |\r
834             ((long) (palettep[i].green >> 2)) << 8 |\r
835             ((long) (palettep[i].blue >> 2)) << 16;\r
836 \r
837       (void) _remapallpalette(vga_palp);        /* Remap entire palette */\r
838 \r
839       free(vga_palp);   /* Free the VGA palette buffer                  */\r
840 \r
841       break;\r
842 \r
843     default:            /* Other modes not supported                    */\r
844 \r
845       status = FALSE;\r
846 \r
847       break;\r
848   }\r
849 \r
850   return (status);\r
851 }\r
852 \f\r
853 /*\r
854  *************************************************************************\r
855  *\r
856  *  PCX_CGA_PALETTE - Select CGA Palette\r
857  *\r
858  *  Purpose:    To set the Color Graphics Adapter (CGA) display palette\r
859  *              according to a PCX file palette.\r
860  *\r
861  *  Setup:      static void pcx_cga_palette\r
862  *              (\r
863  *                PCX_PAL *palettep,\r
864  *                int vmode\r
865  *              )\r
866  *\r
867  *  Where:      palettep is a pointer to a PCX file palette.\r
868  *              vmode is the MS-DOS video mode.  Valid values are:\r
869  *\r
870  *                0x04 -        320 x 200 4-color CGA\r
871  *                0x05 -        320 x 200 4-color CGA (color burst off)\r
872  *                0x06 -        640 x 200 2-color CGA\r
873  *\r
874  *  Note:       ZSoft's PC Paintbrush products no longer support the CGA\r
875  *              color palette.  When a CGA color palette is encountered,\r
876  *              PC Paintbrush maps it to a monochrome (black and white)\r
877  *              palette.\r
878  *\r
879  *              MS-DOS video mode 0x05 (320 x 200 monochrome CGA display,\r
880  *              color burst off) will only display a monochrome image on\r
881  *              a composite video monitor (typically a television set with\r
882  *              an RF adapter).  All other monitors will display a color\r
883  *              palette in this mode (which is different for CGA and EGA\r
884  *              or VGA display adapters).\r
885  *\r
886  *              The "background" color is actually the foreground color\r
887  *              (i.e. - the color of activated pixels) for MS-DOS video\r
888  *              mode 0x06.  The background color is black for CGA display\r
889  *              adapters.\r
890  *\r
891  *************************************************************************\r
892  */\r
893 \r
894 static void pcx_cga_palette\r
895 (\r
896   PCX_PAL *palettep,\r
897   int vmode\r
898 )\r
899 {\r
900   short pal_num;        /* Palette number                               */\r
901   BOOL sel_flag;        /* Palette selector bit flag                    */\r
902   BOOL int_flag;        /* Intensity bit flag                           */\r
903   union REGS regs;      /* 80x86 register values                        */\r
904 \r
905   /* Set the background color                                           */\r
906 \r
907   regs.h.ah = 0x0b;     /* Select "Set Color Palette" BIOS routine      */\r
908   regs.h.bh = 0;\r
909 \r
910   regs.h.bl = (unsigned char) PCX_CGA_BKGND(palettep);\r
911 \r
912   int86(0x10, &regs, &regs);    /* Call BIOS video service              */\r
913 \r
914   if (vmode != 0x06)    /* Select the CGA color palette                 */\r
915   {\r
916     /* Check the palette selector bit flag                              */\r
917 \r
918     sel_flag = PCX_CGA_SELECT(palettep) ? TRUE : FALSE;\r
919 \r
920     /* Check the intensity bit flag                                     */\r
921 \r
922     int_flag = PCX_CGA_INTENSITY(palettep) ? TRUE : FALSE;\r
923 \r
924     /* Determine the CGA palette number                                 */\r
925 \r
926     if (int_flag == TRUE)       /* Intensity = bright                   */\r
927     {\r
928       if (sel_flag == TRUE)\r
929         pal_num = 3;    /* Light cyan - light magenta - white           */\r
930       else\r
931         pal_num = 1;    /* Cyan - magenta - light grey                  */\r
932     }\r
933     else                        /* Intensity = dim                      */\r
934     {\r
935       if (sel_flag == TRUE)\r
936         pal_num = 2;    /* Light green - light red - yellow             */\r
937       else\r
938         pal_num = 0;    /* Green - red - brown                          */\r
939     }\r
940 \r
941     /* Select the foreground color palette                              */\r
942 \r
943     (void) _selectpalette(pal_num);\r
944   }\r
945 }\r
946 \f\r
947 /*\r
948  *************************************************************************\r
949  *\r
950  *  PCX_PUT_HERC - Display Hercules PCX Line\r
951  *\r
952  *  Purpose:    To copy a decoded PCX image scan line to a Hercules\r
953  *              monochrome graphics display adapter buffer.\r
954  *\r
955  *  Setup:      static void pcx_put_herc\r
956  *              (\r
957  *                PCX_WORKBLK *wbp,\r
958  *                unsigned char _far *linep,\r
959  *                int line_num\r
960  *              )\r
961  *\r
962  *  Where:      wbp is a PCX image file workblock pointer.\r
963  *              linep is a PCX scan line buffer pointer.\r
964  *              line_num is the scan line number.\r
965  *\r
966  *************************************************************************\r
967  */\r
968 \r
969 void pcx_put_herc\r
970 (\r
971   PCX_WORKBLK *wbp,\r
972   unsigned char _far *linep,\r
973   int line_num\r
974 )\r
975 {\r
976   unsigned char _far *displayp;         /* Display buffer pointer       */\r
977 \r
978   /* Mask off unseen pixels                                             */\r
979 \r
980   linep[wbp->num_bytes - 1] &= wbp->mask;\r
981 \r
982   /* Calculate Hercules display buffer pointer                          */\r
983 \r
984   displayp = (unsigned char _far *) (0xb0000000L + wbp->page_offset) +\r
985       ((line_num >> 2) * 90) + 0x2000 * (line_num & 3);\r
986 \r
987   /* Copy data from the scan line buffer to the Hercules display buffer */\r
988 \r
989   (void) _fmemcpy(displayp, linep, wbp->num_bytes);\r
990 }\r
991 \f\r
992 /*\r
993  *************************************************************************\r
994  *\r
995  *  PCX_PUT_CGA - Display CGA PCX Line\r
996  *\r
997  *  Purpose:    To copy a decoded PCX image scan line to a CGA display\r
998  *              adapter buffer.\r
999  *\r
1000  *  Setup:      static void pcx_put_cga\r
1001  *              (\r
1002  *                PCX_WORKBLK *wbp,\r
1003  *                unsigned char _far *linep,\r
1004  *                int line_num\r
1005  *              )\r
1006  *\r
1007  *  Where:      wbp is a PCX image file workblock pointer.\r
1008  *              linep is a PCX scan line buffer pointer.\r
1009  *              line_num is the scan line number.\r
1010  *\r
1011  *************************************************************************\r
1012  */\r
1013 \r
1014 static void pcx_put_cga\r
1015 (\r
1016   PCX_WORKBLK *wbp,\r
1017   unsigned char _far *linep,\r
1018   int line_num\r
1019 )\r
1020 {\r
1021   unsigned char _far *displayp;         /* Display buffer pointer       */\r
1022 \r
1023   /* Mask off unseen pixels                                             */\r
1024 \r
1025   linep[wbp->num_bytes - 1] &= wbp->mask;\r
1026 \r
1027   /* Calculate CGA display buffer pointer                               */\r
1028 \r
1029   displayp = (unsigned char _far *) 0xb8000000L + ((line_num >> 1) * 80)\r
1030       + 0x2000 * (line_num & 1);\r
1031 \r
1032   /* Copy data from the scan line buffer to the CGA display buffer      */\r
1033 \r
1034   (void) _fmemcpy(displayp, linep, wbp->num_bytes);\r
1035 }\r
1036 \f\r
1037 /*\r
1038  *************************************************************************\r
1039  *\r
1040  *  PCX_PUT_EGA - Display EGA/VGA PCX Line\r
1041  *\r
1042  *  Purpose:    To copy a decoded PCX image scan line to an EGA/VGA\r
1043  *              display adapter buffer.\r
1044  *\r
1045  *  Setup:      static void pcx_put_ega\r
1046  *              (\r
1047  *                PCX_WORKBLK *wbp,\r
1048  *                unsigned char _far *linep,\r
1049  *                int line_num\r
1050  *              )\r
1051  *\r
1052  *  Where:      wbp is a PCX image file workblock pointer.\r
1053  *              linep is a PCX scan line buffer pointer.\r
1054  *              line_num is the scan line number.\r
1055  *\r
1056  *************************************************************************\r
1057  */\r
1058 \r
1059 static void pcx_put_ega\r
1060 (\r
1061   PCX_WORKBLK *wbp,\r
1062   unsigned char _far *linep,\r
1063   int line_num\r
1064 )\r
1065 {\r
1066   int plane_num;                /* EGA/VGA color plane number           */\r
1067   int plane_mask;               /* EGA/VGA color plane mask             */\r
1068   unsigned char _far *displayp; /* Display buffer pointer               */\r
1069 \r
1070   /* Calculate buffer pointer                                           */\r
1071 \r
1072   displayp = (unsigned char _far *) (0xa0000000L + wbp->page_offset) +\r
1073       line_num * 80;\r
1074 \r
1075   outpw(0x03ce, 0x0005);        /* Select EGA/VGA write mode 0          */\r
1076 \r
1077   /* Copy PCX scan line data to each color plane                        */\r
1078 \r
1079   plane_mask = 0x0100;          /* Start with color plane 0             */\r
1080 \r
1081   for (plane_num = 0; plane_num < (int) wbp->header.nplanes; plane_num++)\r
1082   {\r
1083     /* Mask off unseen pixels                                           */\r
1084 \r
1085     linep[wbp->num_bytes - 1] &= wbp->mask;\r
1086 \r
1087     outpw(0x03c4, plane_mask + 2);      /* Select current color plane   */\r
1088 \r
1089     /* Copy data from the scan line buffer to the EGA/VGA display       */\r
1090 \r
1091     (void) _fmemcpy(displayp, linep, wbp->num_bytes);\r
1092 \r
1093     linep += wbp->header.bppscan;       /* Increment plane offset       */\r
1094 \r
1095     plane_mask <<= 1;   /* Sequence plane mask                          */\r
1096   }\r
1097 \r
1098   outpw(0x03c4, 0x0f02);        /* Select all color planes              */\r
1099 }\r
1100 \f\r
1101 /*\r
1102  *************************************************************************\r
1103  *\r
1104  *  PCX_PUT_VGA - Display VGA PCX Line\r
1105  *\r
1106  *  Purpose:    To copy a decoded PCX image scan line to a VGA display\r
1107  *              adapter buffer.\r
1108  *\r
1109  *  Setup:      static void pcx_put_vga\r
1110  *              (\r
1111  *                PCX_WORKBLK *wbp,\r
1112  *                unsigned char _far *linep,\r
1113  *                int line_num\r
1114  *              )\r
1115  *\r
1116  *  Where:      wbp is a PCX image file workblock pointer.\r
1117  *              linep is a PCX scan line buffer pointer.\r
1118  *              line_num is the scan line number.\r
1119  *\r
1120  *************************************************************************\r
1121  */\r
1122 \r
1123 static void pcx_put_vga\r
1124 (\r
1125   PCX_WORKBLK *wbp,\r
1126   unsigned char _far *linep,\r
1127   int line_num\r
1128 )\r
1129 {\r
1130   unsigned char _far *displayp;         /* Display buffer pointer       */\r
1131 \r
1132   /* Calculate buffer pointer                                           */\r
1133 \r
1134   displayp = (unsigned char _far *) 0xa0000000L + line_num * 320;\r
1135 \r
1136   /* Copy data from the scan line buffer to the VGA display buffer      */\r
1137 \r
1138   (void) _fmemcpy(displayp, linep, wbp->num_bytes);\r
1139 }\r
1140 \r