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