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