This commit was manufactured by cvs2svn to create tag 'd2x-0_1_2'.
[btb/d2x.git] / 2d / pcx.c
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  * 
15  * Routines to read/write pcx images.
16  * 
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include <conf.h>
21 #endif
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "gr.h"
28 #include "grdef.h"
29 #include "u_mem.h"
30 #include "pcx.h"
31 #include "cfile.h"
32
33 int pcx_encode_byte(ubyte byt, ubyte cnt, FILE * fid);
34 int pcx_encode_line(ubyte *inBuff, int inLen, FILE * fp);
35
36 /* PCX Header data type */
37 typedef struct  {
38         ubyte           Manufacturer;
39         ubyte           Version;
40         ubyte           Encoding;
41         ubyte           BitsPerPixel;
42         short           Xmin;
43         short           Ymin;
44         short           Xmax;
45         short           Ymax;
46         short           Hdpi;
47         short           Vdpi;
48         ubyte           ColorMap[16][3];
49         ubyte           Reserved;
50         ubyte           Nplanes;
51         short           BytesPerLine;
52         ubyte           filler[60];
53 } PCXHeader;
54
55
56 int pcx_read_bitmap( char * filename, grs_bitmap * bmp,int bitmap_type ,ubyte * palette )
57 {
58         PCXHeader header;
59         CFILE * PCXfile;
60         int i, row, col, count, xsize, ysize;
61         ubyte data, *pixdata;
62
63         PCXfile = cfopen( filename , "rb" );
64         if ( !PCXfile )
65                 return PCX_ERROR_OPENING;
66
67         // read 128 char PCX header
68         if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1)        {
69                 cfclose( PCXfile );
70                 return PCX_ERROR_NO_HEADER;
71         }
72
73         // Is it a 256 color PCX file?
74         if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5))      {
75                 cfclose( PCXfile );
76                 return PCX_ERROR_WRONG_VERSION;
77         }
78
79         // Find the size of the image
80         xsize = header.Xmax - header.Xmin + 1;
81         ysize = header.Ymax - header.Ymin + 1;
82
83         if ( bitmap_type == BM_LINEAR ) {
84                 if ( bmp->bm_data == NULL )     {
85                         gr_init_bitmap_alloc (bmp, bitmap_type, 0, 0, xsize, ysize, xsize);
86                 }
87         }
88
89         if ( bmp->bm_type == BM_LINEAR )        {
90                 for (row=0; row< ysize ; row++)      {
91                         pixdata = &bmp->bm_data[bmp->bm_rowsize*row];
92                         for (col=0; col< xsize ; )      {
93                                 if (cfread( &data, 1, 1, PCXfile )!=1 ) {
94                                         cfclose( PCXfile );     
95                                         return PCX_ERROR_READING;
96                                 }
97                                 if ((data & 0xC0) == 0xC0)     {
98                                         count =  data & 0x3F;
99                                         if (cfread( &data, 1, 1, PCXfile )!=1 ) {
100                                                 cfclose( PCXfile );     
101                                                 return PCX_ERROR_READING;
102                                         }
103                                         memset( pixdata, data, count );
104                                         pixdata += count;
105                                         col += count;
106                                 } else {
107                                         *pixdata++ = data;
108                                         col++;
109                                 }
110                         }
111                 }
112         } else {
113                 for (row=0; row< ysize ; row++)      {
114                         for (col=0; col< xsize ; )      {
115                                 if (cfread( &data, 1, 1, PCXfile )!=1 ) {
116                                         cfclose( PCXfile );     
117                                         return PCX_ERROR_READING;
118                                 }
119                                 if ((data & 0xC0) == 0xC0)     {
120                                         count =  data & 0x3F;
121                                         if (cfread( &data, 1, 1, PCXfile )!=1 ) {
122                                                 cfclose( PCXfile );     
123                                                 return PCX_ERROR_READING;
124                                         }
125                                         for (i=0;i<count;i++)
126                                                 gr_bm_pixel( bmp, col+i, row, data );
127                                         col += count;
128                                 } else {
129                                         gr_bm_pixel( bmp, col, row, data );
130                                         col++;
131                                 }
132                         }
133                 }
134         }
135
136         // Read the extended palette at the end of PCX file
137         if ( palette != NULL )  {
138                 // Read in a character which should be 12 to be extended palette file
139                 if (cfread( &data, 1, 1, PCXfile )==1)  {
140                         if ( data == 12 )       {
141                                 if (cfread(palette,768, 1, PCXfile)!=1) {
142                                         cfclose( PCXfile );
143                                         return PCX_ERROR_READING;
144                                 }
145                                 for (i=0; i<768; i++ )
146                                         palette[i] >>= 2;
147                         }
148                 } else {
149                         cfclose( PCXfile );     
150                         return PCX_ERROR_NO_PALETTE;
151                 }
152         }
153         cfclose(PCXfile);
154         return PCX_ERROR_NONE;
155 }
156
157 int pcx_write_bitmap( char * filename, grs_bitmap * bmp, ubyte * palette )
158 {
159         int retval;
160         int i;
161         ubyte data;
162         PCXHeader header;
163         FILE * PCXfile;
164
165         memset( &header, 0, sizeof( PCXHeader ) );
166
167         header.Manufacturer = 10;
168         header.Encoding = 1;
169         header.Nplanes = 1;
170         header.BitsPerPixel = 8;
171         header.Version = 5;
172         header.Xmax = bmp->bm_w-1;
173         header.Ymax = bmp->bm_h-1;
174         header.BytesPerLine = bmp->bm_w;
175
176         PCXfile = fopen( filename , "wb" );
177         if ( !PCXfile )
178                 return PCX_ERROR_OPENING;
179
180         if ( fwrite( &header, sizeof( PCXHeader ), 1, PCXfile ) != 1 )  {
181                 fclose( PCXfile );
182                 return PCX_ERROR_WRITING;
183         }
184
185         for (i=0; i<bmp->bm_h; i++ )    {
186                 if (!pcx_encode_line( &bmp->bm_data[bmp->bm_rowsize*i], bmp->bm_w, PCXfile ))   {
187                         fclose( PCXfile );
188                         return PCX_ERROR_WRITING;
189                 }
190         }
191
192         // Mark an extended palette     
193         data = 12;
194         if (fwrite( &data, 1, 1, PCXfile )!=1)  {
195                 fclose( PCXfile );
196                 return PCX_ERROR_WRITING;
197         }
198
199         // Write the extended palette
200         for (i=0; i<768; i++ )  
201                 palette[i] <<= 2;
202         
203         retval = fwrite( palette, 768, 1, PCXfile );
204
205         for (i=0; i<768; i++ )  
206                 palette[i] >>= 2;
207
208         if (retval !=1) {
209                 fclose( PCXfile );
210                 return PCX_ERROR_WRITING;
211         }
212
213         fclose( PCXfile );
214         return PCX_ERROR_NONE;
215
216 }
217
218 // returns number of bytes written into outBuff, 0 if failed 
219 int pcx_encode_line(ubyte *inBuff, int inLen, FILE * fp)
220 {  
221         ubyte this, last;
222         int srcIndex, i;
223         register int total;
224         register ubyte runCount;        // max single runlength is 63
225         total = 0;
226         last = *(inBuff);               
227         runCount = 1;
228
229         for (srcIndex = 1; srcIndex < inLen; srcIndex++) {
230                 this = *(++inBuff);
231                 if (this == last)       {
232                         runCount++;                     // it encodes
233                         if (runCount == 63)     {
234                                 if (!(i=pcx_encode_byte(last, runCount, fp)))
235                                         return(0);
236                                 total += i;
237                                 runCount = 0;
238                         }
239                 } else {        // this != last
240                         if (runCount)   {
241                                 if (!(i=pcx_encode_byte(last, runCount, fp)))
242                                         return(0);
243                                 total += i;
244                         }
245                         last = this;
246                         runCount = 1;
247                 }
248         }       
249
250         if (runCount)   {               // finish up
251                 if (!(i=pcx_encode_byte(last, runCount, fp)))
252                         return 0;
253                 return total + i;
254         }
255         return total;
256 }
257
258 // subroutine for writing an encoded byte pair 
259 // returns count of bytes written, 0 if error
260 int pcx_encode_byte(ubyte byt, ubyte cnt, FILE * fid) 
261 {
262         if (cnt) {
263                 if ( (cnt==1) && (0xc0 != (0xc0 & byt)) )       {
264                         if(EOF == putc((int)byt, fid))
265                                 return 0;       // disk write error (probably full)
266                         return 1;
267                 } else {
268                         if(EOF == putc((int)0xC0 | cnt, fid))
269                                 return 0;       // disk write error
270                         if(EOF == putc((int)byt, fid))
271                                 return 0;       // disk write error
272                         return 2;
273                 }
274         }
275         return 0;
276 }
277
278 //text for error messges
279 char pcx_error_messages[] = {
280         "No error.\0"
281         "Error opening file.\0"
282         "Couldn't read PCX header.\0"
283         "Unsupported PCX version.\0"
284         "Error reading data.\0"
285         "Couldn't find palette information.\0"
286         "Error writing data.\0"
287 };
288
289
290 //function to return pointer to error message
291 char *pcx_errormsg(int error_number)
292 {
293         char *p = pcx_error_messages;
294
295         while (error_number--) {
296
297                 if (!p) return NULL;
298
299                 p += strlen(p)+1;
300
301         }
302
303         return p;
304 }
305
306 // fullscreen loading, 10/14/99 Jan Bobrowski
307
308 int pcx_read_fullscr(char * filename, ubyte * palette)
309 {
310         int pcx_error;
311         grs_bitmap bm;
312         gr_init_bitmap_data(&bm);
313         pcx_error = pcx_read_bitmap(filename, &bm, BM_LINEAR, palette);
314         if (pcx_error == PCX_ERROR_NONE)
315                 show_fullscr(&bm);
316         gr_free_bitmap_data(&bm);
317         return pcx_error;
318 }