home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / 2d / pcx.c < prev    next >
Text File  |  1998-06-08  |  8KB  |  336 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: f:/miner/source/2d/rcs/pcx.c $
  15.  * $Revision: 1.6 $
  16.  * $Author: john $
  17.  * $Date: 1995/03/01 15:38:12 $
  18.  * 
  19.  * Routines to read/write pcx images.
  20.  * 
  21.  * $Log: pcx.c $
  22.  * Revision 1.6  1995/03/01  15:38:12  john
  23.  * Better ModeX support.
  24.  * 
  25.  * Revision 1.5  1995/01/21  17:54:17  john
  26.  * Added pcx reader for modes other than modex.
  27.  * 
  28.  * Revision 1.4  1994/12/08  19:03:56  john
  29.  * Made functions use cfile.
  30.  * 
  31.  * Revision 1.3  1994/11/29  02:53:24  john
  32.  * Added error messages; made call be more similiar to iff.
  33.  * 
  34.  * Revision 1.2  1994/11/28  20:03:50  john
  35.  * Added PCX functions.
  36.  * 
  37.  * Revision 1.1  1994/11/28  19:57:56  john
  38.  * Initial revision
  39.  * 
  40.  * 
  41.  */
  42.  
  43.  
  44. #pragma off (unreferenced)
  45. static char rcsid[] = "$Id: pcx.c 1.6 1995/03/01 15:38:12 john Exp $";
  46. #pragma on (unreferenced)
  47.  
  48. #include <stdlib.h>
  49. #include <stdio.h>
  50. #include <string.h>
  51.  
  52. #include "gr.h"
  53. #include "mem.h"
  54. #include "pcx.h"
  55. #include "cfile.h"
  56.  
  57. /* PCX Header data type */
  58. typedef struct    {
  59.     ubyte        Manufacturer;
  60.     ubyte        Version;
  61.     ubyte        Encoding;
  62.     ubyte        BitsPerPixel;
  63.     short        Xmin;
  64.     short        Ymin;
  65.     short        Xmax;
  66.     short        Ymax;
  67.     short        Hdpi;
  68.     short        Vdpi;
  69.     ubyte        ColorMap[16][3];
  70.     ubyte        Reserved;
  71.     ubyte        Nplanes;
  72.     short        BytesPerLine;
  73.     ubyte        filler[60];
  74. } PCXHeader;
  75.  
  76.  
  77. int pcx_read_bitmap( char * filename, grs_bitmap * bmp,int bitmap_type ,ubyte * palette )
  78. {
  79.     PCXHeader header;
  80.     CFILE * PCXfile;
  81.     int i, row, col, count, xsize, ysize;
  82.     ubyte data, *pixdata;
  83.  
  84.     PCXfile = cfopen( filename , "rb" );
  85.     if ( !PCXfile )
  86.         return PCX_ERROR_OPENING;
  87.  
  88.     // read 128 char PCX header
  89.     if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1)    {
  90.         cfclose( PCXfile );
  91.         return PCX_ERROR_NO_HEADER;
  92.     }
  93.  
  94.     // Is it a 256 color PCX file?
  95.     if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5))    {
  96.         cfclose( PCXfile );
  97.         return PCX_ERROR_WRONG_VERSION;
  98.     }
  99.  
  100.     // Find the size of the image
  101.     xsize = header.Xmax - header.Xmin + 1;
  102.     ysize = header.Ymax - header.Ymin + 1;
  103.  
  104.     if ( bitmap_type == BM_LINEAR )    {
  105.         if ( bmp->bm_data == NULL )    {
  106.             memset( bmp, 0, sizeof( grs_bitmap ) );
  107.             bmp->bm_data = malloc( xsize * ysize );
  108.             if ( bmp->bm_data == NULL )    {
  109.                 cfclose( PCXfile );
  110.                 return PCX_ERROR_MEMORY;
  111.             }
  112.             bmp->bm_w = bmp->bm_rowsize = xsize;
  113.             bmp->bm_h = ysize;
  114.             bmp->bm_type = bitmap_type;
  115.         }
  116.     }
  117.  
  118.     if ( bmp->bm_type == BM_LINEAR )    {
  119.         for (row=0; row< ysize ; row++)      {
  120.             pixdata = &bmp->bm_data[bmp->bm_rowsize*row];
  121.             for (col=0; col< xsize ; )      {
  122.                 if (cfread( &data, 1, 1, PCXfile )!=1 )    {
  123.                     cfclose( PCXfile );    
  124.                     return PCX_ERROR_READING;
  125.                 }
  126.                 if ((data & 0xC0) == 0xC0)     {
  127.                     count =  data & 0x3F;
  128.                     if (cfread( &data, 1, 1, PCXfile )!=1 )    {
  129.                         cfclose( PCXfile );    
  130.                         return PCX_ERROR_READING;
  131.                     }
  132.                     memset( pixdata, data, count );
  133.                     pixdata += count;
  134.                     col += count;
  135.                 } else {
  136.                     *pixdata++ = data;
  137.                     col++;
  138.                 }
  139.             }
  140.         }
  141.     } else {
  142.         for (row=0; row< ysize ; row++)      {
  143.             for (col=0; col< xsize ; )      {
  144.                 if (cfread( &data, 1, 1, PCXfile )!=1 )    {
  145.                     cfclose( PCXfile );    
  146.                     return PCX_ERROR_READING;
  147.                 }
  148.                 if ((data & 0xC0) == 0xC0)     {
  149.                     count =  data & 0x3F;
  150.                     if (cfread( &data, 1, 1, PCXfile )!=1 )    {
  151.                         cfclose( PCXfile );    
  152.                         return PCX_ERROR_READING;
  153.                     }
  154.                     for (i=0;i<count;i++)
  155.                         gr_bm_pixel( bmp, col+i, row, data );
  156.                     col += count;
  157.                 } else {
  158.                     gr_bm_pixel( bmp, col, row, data );
  159.                     col++;
  160.                 }
  161.             }
  162.         }
  163.     }
  164.  
  165.     // Read the extended palette at the end of PCX file
  166.     if ( palette != NULL )    {
  167.         // Read in a character which should be 12 to be extended palette file
  168.         if (cfread( &data, 1, 1, PCXfile )==1)    {
  169.             if ( data == 12 )    {
  170.                 if (cfread(palette,768, 1, PCXfile)!=1)    {
  171.                     cfclose( PCXfile );
  172.                     return PCX_ERROR_READING;
  173.                 }
  174.                 for (i=0; i<768; i++ )
  175.                     palette[i] >>= 2;
  176.             }
  177.         } else {
  178.             cfclose( PCXfile );    
  179.             return PCX_ERROR_NO_PALETTE;
  180.         }
  181.     }
  182.     cfclose(PCXfile);
  183.     return PCX_ERROR_NONE;
  184. }
  185.  
  186. int pcx_write_bitmap( char * filename, grs_bitmap * bmp, ubyte * palette )
  187. {
  188.     int retval;
  189.     int i;
  190.     ubyte data;
  191.     PCXHeader header;
  192.     FILE * PCXfile;
  193.  
  194.     memset( &header, 0, sizeof( PCXHeader ) );
  195.  
  196.     header.Manufacturer = 10;
  197.     header.Encoding = 1;
  198.     header.Nplanes = 1;
  199.     header.BitsPerPixel = 8;
  200.     header.Version = 5;
  201.     header.Xmax = bmp->bm_w-1;
  202.     header.Ymax = bmp->bm_h-1;
  203.     header.BytesPerLine = bmp->bm_w;
  204.  
  205.     PCXfile = fopen( filename , "wb" );
  206.     if ( !PCXfile )
  207.         return PCX_ERROR_OPENING;
  208.  
  209.     if ( fwrite( &header, sizeof( PCXHeader ), 1, PCXfile ) != 1 )    {
  210.         fclose( PCXfile );
  211.         return PCX_ERROR_WRITING;
  212.     }
  213.  
  214.     for (i=0; i<bmp->bm_h; i++ )    {
  215.         if (!pcx_encode_line( &bmp->bm_data[bmp->bm_rowsize*i], bmp->bm_w, PCXfile ))    {
  216.             fclose( PCXfile );
  217.             return PCX_ERROR_WRITING;
  218.         }
  219.     }
  220.  
  221.     // Mark an extended palette    
  222.     data = 12;
  223.     if (fwrite( &data, 1, 1, PCXfile )!=1)    {
  224.         fclose( PCXfile );
  225.         return PCX_ERROR_WRITING;
  226.     }
  227.  
  228.     // Write the extended palette
  229.     for (i=0; i<768; i++ )    
  230.         palette[i] <<= 2;
  231.     
  232.     retval = fwrite( palette, 768, 1, PCXfile );
  233.  
  234.     for (i=0; i<768; i++ )    
  235.         palette[i] >>= 2;
  236.  
  237.     if (retval !=1)    {
  238.         fclose( PCXfile );
  239.         return PCX_ERROR_WRITING;
  240.     }
  241.  
  242.     fclose( PCXfile );
  243.     return PCX_ERROR_NONE;
  244.  
  245. }
  246.  
  247. // returns number of bytes written into outBuff, 0 if failed 
  248. int pcx_encode_line(ubyte *inBuff, int inLen, FILE * fp)
  249. {  
  250.     ubyte this, last;
  251.     int srcIndex, i;
  252.     register int total;
  253.     register ubyte runCount;     // max single runlength is 63
  254.     total = 0;
  255.     last = *(inBuff);        
  256.     runCount = 1;
  257.  
  258.     for (srcIndex = 1; srcIndex < inLen; srcIndex++) {
  259.         this = *(++inBuff);
  260.         if (this == last)    {
  261.             runCount++;            // it encodes
  262.             if (runCount == 63)    {
  263.                 if (!(i=pcx_encode_byte(last, runCount, fp)))
  264.                     return(0);
  265.                 total += i;
  266.                 runCount = 0;
  267.             }
  268.         } else {       // this != last
  269.             if (runCount)    {
  270.                 if (!(i=pcx_encode_byte(last, runCount, fp)))
  271.                     return(0);
  272.                 total += i;
  273.             }
  274.             last = this;
  275.             runCount = 1;
  276.         }
  277.     }    
  278.  
  279.     if (runCount)    {        // finish up
  280.         if (!(i=pcx_encode_byte(last, runCount, fp)))
  281.             return 0;
  282.         return total + i;
  283.     }
  284.     return total;
  285. }
  286.  
  287. // subroutine for writing an encoded byte pair 
  288. // returns count of bytes written, 0 if error
  289. int pcx_encode_byte(ubyte byt, ubyte cnt, FILE * fid) 
  290. {
  291.     if (cnt) {
  292.         if ( (cnt==1) && (0xc0 != (0xc0 & byt)) )    {
  293.             if(EOF == putc((int)byt, fid))
  294.                 return 0;     // disk write error (probably full)
  295.             return 1;
  296.         } else {
  297.             if(EOF == putc((int)0xC0 | cnt, fid))
  298.                 return 0;     // disk write error
  299.             if(EOF == putc((int)byt, fid))
  300.                 return 0;     // disk write error
  301.             return 2;
  302.         }
  303.     }
  304.     return 0;
  305. }
  306.  
  307. //text for error messges
  308. char pcx_error_messages[] = {
  309.     "No error.\0"
  310.     "Error opening file.\0"
  311.     "Couldn't read PCX header.\0"
  312.     "Unsupported PCX version.\0"
  313.     "Error reading data.\0"
  314.     "Couldn't find palette information.\0"
  315.     "Error writing data.\0"
  316. };
  317.  
  318.  
  319. //function to return pointer to error message
  320. char *pcx_errormsg(int error_number)
  321. {
  322.     char *p = pcx_error_messages;
  323.  
  324.     while (error_number--) {
  325.  
  326.         if (!p) return NULL;
  327.  
  328.         p += strlen(p)+1;
  329.  
  330.     }
  331.  
  332.     return p;
  333.  
  334. }
  335. 
  336.