]> icculus.org git repositories - taylor/freespace2.git/blob - src/pcxutils/pcxutils.cpp
properly poll for window events when fullscreen or resizable
[taylor/freespace2.git] / src / pcxutils / pcxutils.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/PcxUtils/pcxutils.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * code to deal with pcx files
16  *
17  * $Log$
18  * Revision 1.4  2004/06/11 02:05:16  tigital
19  * byte-swapping changes for bigendian systems
20  *
21  * Revision 1.3  2002/06/09 04:41:25  relnev
22  * added copyright header
23  *
24  * Revision 1.2  2002/05/07 03:16:48  theoddone33
25  * The Great Newline Fix
26  *
27  * Revision 1.1.1.1  2002/05/03 03:28:10  root
28  * Initial import.
29  *
30  * 
31  * 11    8/10/99 6:54p Dave
32  * Mad optimizations. Added paging to the nebula effect.
33  * 
34  * 10    7/13/99 1:16p Dave
35  * 32 bit support. Whee!
36  * 
37  * 9     2/05/99 12:52p Dave
38  * Fixed Glide nondarkening textures.
39  * 
40  * 8     2/03/99 6:06p Dave
41  * Groundwork for FS2 PXO usertracker support.  Gametracker support next.
42  * 
43  * 7     2/03/99 11:44a Dave
44  * Fixed d3d transparent textures.
45  * 
46  * 6     12/01/98 5:54p Dave
47  * Simplified the way pixel data is swizzled. Fixed tga bitmaps to work
48  * properly in D3D and Glide.
49  * 
50  * 5     12/01/98 4:46p Dave
51  * Put in targa bitmap support (16 bit).
52  * 
53  * 4     12/01/98 8:06a Dave
54  * Temporary checkin to fix some texture transparency problems in d3d.
55  * 
56  * 3     11/30/98 1:07p Dave
57  * 16 bit conversion, first run.
58  * 
59  * 2     10/07/98 10:53a Dave
60  * Initial checkin.
61  * 
62  * 1     10/07/98 10:50a Dave
63  * 
64  * 16    1/19/98 11:37p Lawrance
65  * Fixing Optimization build warnings
66  * 
67  * 15    9/09/97 3:39p Sandeep
68  * warning level 4 bugs
69  * 
70  * 14    9/03/97 4:32p John
71  * changed bmpman to only accept ani and pcx's.  made passing .pcx or .ani
72  * to bm_load functions not needed.   Made bmpman keep track of palettes
73  * for bitmaps not mapped into game palettes.
74  * 
75  * 13    7/20/97 6:59p Lawrance
76  * fixed bug that was writing out PCX files with an extra bogus line
77  * 
78  * 12    6/05/97 6:07p John
79  * fixed warning
80  * 
81  * 11    6/05/97 3:59p John
82  * Fixed a bug in PCX reader
83  * 
84  * 10    2/25/97 12:06p John
85  * fixed a pcx potential bug.
86  * 
87  * 9     2/25/97 12:03p John
88  * fixed a pcx reading bug.
89  * 
90  * 8     2/20/97 4:18p John
91  * fixed bug reading odd-width pcx files
92  * 
93  * 7     11/26/96 9:28a Allender
94  * get palette info when getting pcx info
95  * 
96  * 6     11/18/96 12:36p John
97  * Added code to dump screen to a PCX file.
98  * 
99  * 5     11/13/96 4:51p Allender
100  * started overhaul of bitmap manager.  bm_load no longer actually load
101  * the data, only the info for the bitmap.  Locking the bitmap now forces
102  * load when no data present (or will if bpp changes)
103  *
104  * $NoKeywords: $
105  */
106
107 #include "cfile.h"
108 #include "pcxutils.h"
109 #include "palman.h"
110 #include "bmpman.h"
111
112 /* PCX Header data type */
113 typedef struct  {
114         ubyte           Manufacturer;
115         ubyte           Version;
116         ubyte           Encoding;
117         ubyte           BitsPerPixel;
118         short           Xmin;
119         short           Ymin;
120         short           Xmax;
121         short           Ymax;
122         short           Hdpi;
123         short           Vdpi;
124         ubyte           ColorMap[16][3];
125         ubyte           Reserved;
126         ubyte           Nplanes;
127         short           BytesPerLine;
128         ubyte           filler[60];
129 } PCXHeader;
130
131 // reads header information from the PCX file into the bitmap pointer
132 int pcx_read_header(char *real_filename, int *w, int *h, ubyte *pal )
133 {
134         PCXHeader header;
135         CFILE * PCXfile;
136         char filename[MAX_FILENAME_LEN];
137                 
138         SDL_strlcpy( filename, real_filename, SDL_arraysize(filename) );
139         char *p = SDL_strchr( filename, '.' );
140         if ( p ) *p = 0;
141         SDL_strlcat( filename, ".pcx", SDL_arraysize(filename) );
142
143         PCXfile = cfopen( filename , "rb" );
144         if ( !PCXfile )
145                 return PCX_ERROR_OPENING;
146
147         // read 128 char PCX header
148         if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1)        {
149                 cfclose( PCXfile );
150                 return PCX_ERROR_NO_HEADER;
151         }
152         header.Xmin = INTEL_SHORT( header.Xmin );
153         header.Ymin = INTEL_SHORT( header.Ymin );
154         header.Xmax = INTEL_SHORT( header.Xmax );
155         header.Ymax = INTEL_SHORT( header.Ymax );
156         header.Hdpi = INTEL_SHORT( header.Hdpi );
157         header.Vdpi = INTEL_SHORT( header.Vdpi );
158         for ( int i=0; i<16; i++ ){
159             for ( int j=0; j<3; j++){
160                 header.ColorMap[i][j] = INTEL_INT( header.ColorMap[i][j] );
161             }
162         }
163         header.BytesPerLine = INTEL_SHORT( header.BytesPerLine );
164         for ( int i=0; i<60; i++ ){
165             header.filler[i] = INTEL_INT( header.filler[i] );
166         }
167
168         // Is it a 256 color PCX file?
169         if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5))      {
170                 cfclose( PCXfile );
171                 return PCX_ERROR_WRONG_VERSION;
172         }
173
174         if (w) *w = header.Xmax - header.Xmin + 1;
175         if (h) *h = header.Ymax - header.Ymin + 1;
176         
177         if ( pal ) {
178                 cfseek( PCXfile, -768, CF_SEEK_END );
179                 cfread( pal, 3, 256, PCXfile );
180         }
181
182         cfclose(PCXfile);
183         return PCX_ERROR_NONE;
184 }
185
186 // static ubyte Pcx_load[1024*768 + 768 + sizeof(PCXHeader)];
187 // int Pcx_load_offset = 0;
188 // int Pcx_load_size = 0;
189
190 // #define GET_BUF()                    do { buffer = &Pcx_load[Pcx_load_offset]; if(Pcx_load_offset + buffer_size > Pcx_load_size) { buffer_size = Pcx_load_size - Pcx_load_offset; } } while(0);
191 int pcx_read_bitmap_8bpp( char * real_filename, ubyte *org_data, ubyte *palette )
192 {
193                 PCXHeader header;
194         CFILE * PCXfile;
195         int row, col, count, xsize, ysize;
196         ubyte data=0;
197         int buffer_size, buffer_pos;
198         ubyte buffer[1024];
199         ubyte *pixdata;
200         char filename[MAX_FILENAME_LEN];
201                 
202         SDL_strlcpy( filename, real_filename, SDL_arraysize(filename) );
203         char *p = SDL_strchr( filename, '.' );
204         if ( p ) *p = 0;
205         SDL_strlcat( filename, ".pcx", SDL_arraysize(filename) );
206
207         PCXfile = cfopen( filename , "rb" );
208         if ( !PCXfile )
209                 return PCX_ERROR_OPENING;
210
211         // read 128 char PCX header
212         if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1)        {
213                 cfclose( PCXfile );
214                 return PCX_ERROR_NO_HEADER;
215         }
216         header.Xmin = INTEL_SHORT( header.Xmin );
217         header.Ymin = INTEL_SHORT( header.Ymin );
218         header.Xmax = INTEL_SHORT( header.Xmax );
219         header.Ymax = INTEL_SHORT( header.Ymax );
220         header.Hdpi = INTEL_SHORT( header.Hdpi );
221         header.Vdpi = INTEL_SHORT( header.Vdpi );
222
223         header.BytesPerLine = INTEL_SHORT( header.BytesPerLine );
224
225         // Is it a 256 color PCX file?
226         if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5))      {
227                 cfclose( PCXfile );
228                 return PCX_ERROR_WRONG_VERSION;
229         }
230
231         // Find the size of the image
232         xsize = header.Xmax - header.Xmin + 1;
233         ysize = header.Ymax - header.Ymin + 1;
234
235         // Read the extended palette at the end of PCX file
236         // Read in a character which should be 12 to be extended palette file
237
238         cfseek( PCXfile, -768, CF_SEEK_END );
239         cfread( palette, 3, 256, PCXfile );
240         
241         for ( int i=0; i<256; i++ ){                            //tigital
242             palette[i] = INTEL_INT( palette[i] );
243         }
244         cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
245         
246         buffer_size = 1024;
247         buffer_pos = 0;
248         
249 //      SDL_assert( buffer_size == 1024 );      // AL: removed to avoid optimized warning 'unreachable code'
250         buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
251
252         count = 0;
253
254         for (row=0; row<ysize;row++)      {
255                 pixdata = org_data;
256                 for (col=0; col<header.BytesPerLine;col++)     {
257                         if ( count == 0 )       {
258                                 data = buffer[buffer_pos++];
259                                 if ( buffer_pos == buffer_size )        {
260                                         buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
261                                         SDL_assert( buffer_size > 0 );
262                                         buffer_pos = 0;
263                                 }
264                                 if ((data & 0xC0) == 0xC0)     {
265                                         count = data & 0x3F;
266                                         data = buffer[buffer_pos++];
267                                         if ( buffer_pos == buffer_size )        {
268                                                 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
269                                                 SDL_assert( buffer_size > 0 );
270                                                 buffer_pos = 0;
271                                         }
272                                 } else {
273                                         count = 1;
274                                 }
275                         }
276                         if ( col < xsize )
277                                 *pixdata++ = data;
278                         count--;
279                 }
280                 org_data += xsize;
281         }
282         cfclose(PCXfile);
283         return PCX_ERROR_NONE;
284 }
285
286 int pcx_read_bitmap_16bpp( char * real_filename, ubyte *org_data )
287 {
288         PCXHeader header;
289         CFILE * PCXfile;
290         int row, col, count, xsize, ysize;
291         ubyte data=0;
292         int buffer_size, buffer_pos;
293         ubyte buffer[1024];
294         ubyte *pixdata;
295         char filename[MAX_FILENAME_LEN];
296         ubyte palette[768];     
297         ushort bit_16;  
298         ubyte r, g, b, al;
299                 
300         SDL_strlcpy( filename, real_filename, SDL_arraysize(filename) );
301         char *p = SDL_strchr( filename, '.' );
302         if ( p ) *p = 0;
303         SDL_strlcat( filename, ".pcx", SDL_arraysize(filename) );
304
305         PCXfile = cfopen( filename , "rb" );
306         if ( !PCXfile ){
307                 return PCX_ERROR_OPENING;
308         }
309
310         // read 128 char PCX header
311         if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1)        {
312                 cfclose( PCXfile );
313                 return PCX_ERROR_NO_HEADER;
314         }
315
316         header.Xmin = INTEL_SHORT( header.Xmin );
317         header.Ymin = INTEL_SHORT( header.Ymin );
318         header.Xmax = INTEL_SHORT( header.Xmax );
319         header.Ymax = INTEL_SHORT( header.Ymax );
320         header.Hdpi = INTEL_SHORT( header.Hdpi );
321         header.Vdpi = INTEL_SHORT( header.Vdpi );
322
323         header.BytesPerLine = INTEL_SHORT( header.BytesPerLine );
324
325         // Is it a 256 color PCX file?
326         if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5))      {
327                 cfclose( PCXfile );
328                 return PCX_ERROR_WRONG_VERSION;
329         }
330
331         // Find the size of the image
332         xsize = header.Xmax - header.Xmin + 1;
333         ysize = header.Ymax - header.Ymin + 1;
334
335         // Read the extended palette at the end of PCX file
336         // Read in a character which should be 12 to be extended palette file
337
338         cfseek( PCXfile, -768, CF_SEEK_END );
339         cfread( palette, 3, 256, PCXfile );
340         cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
341         
342         buffer_size = 1024;
343         buffer_pos = 0;
344         
345 //      SDL_assert( buffer_size == 1024 );      // AL: removed to avoid optimized warning 'unreachable code'
346         buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
347
348         count = 0;      
349
350         for (row=0; row<ysize;row++)      {
351                 pixdata = org_data;
352                 for (col=0; col<header.BytesPerLine;col++)     {
353                         if ( count == 0 )       {
354                                 data = buffer[buffer_pos++];
355                                 if ( buffer_pos == buffer_size )        {
356                                         buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
357                                         SDL_assert( buffer_size > 0 );
358                                         buffer_pos = 0;
359                                 }
360                                 if ((data & 0xC0) == 0xC0)     {
361                                         count = data & 0x3F;
362                                         data = buffer[buffer_pos++];
363                                         if ( buffer_pos == buffer_size )        {
364                                                 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
365                                                 SDL_assert( buffer_size > 0 );
366                                                 buffer_pos = 0;
367                                         }
368                                 } else {
369                                         count = 1;
370                                 }
371                         }
372                         // stuff the pixel
373                         if ( col < xsize ){                                                             
374                                 // stuff the 24 bit value                               
375                                 r = palette[data*3];
376                                 g = palette[data*3 + 1];
377                                 b = palette[data*3 + 2];
378
379                                 // clear the pixel
380                                 bit_16 = 0;
381                                         
382                                 // if the color matches the transparent color, make it so
383                                 al = 255;
384                                 if((0 == (int)palette[data*3]) && (255 == (int)palette[data*3+1]) && (0 == (int)palette[data*3+2])){
385                                         r = b = 0;
386                                         g = 255;
387                                         al = 0;                                 
388                                 } 
389
390                                 // stuff the color
391                                 bm_set_components((ubyte*)&bit_16, &r, &g, &b, &al);                            
392                                 
393                                 // stuff the pixel
394                                 *((ushort*)pixdata) = bit_16;                           
395                                 pixdata += 2;
396                         }
397                         count--;
398                 }
399
400                 org_data += (xsize * 2);
401         }
402         cfclose(PCXfile);
403         return PCX_ERROR_NONE;
404 }
405
406 int pcx_read_bitmap_16bpp_aabitmap( char * real_filename, ubyte *org_data )
407 {       
408         PCXHeader header;
409         CFILE * PCXfile;
410         int row, col, count, xsize, ysize;
411         ubyte data=0;
412         int buffer_size, buffer_pos;
413         ubyte buffer[1024];
414         ubyte *pixdata;
415         char filename[MAX_FILENAME_LEN];
416         ubyte palette[768];             
417                 
418         SDL_strlcpy( filename, real_filename, SDL_arraysize(filename) );
419         char *p = SDL_strchr( filename, '.' );
420         if ( p ) *p = 0;
421
422         SDL_strlcat( filename, ".pcx", SDL_arraysize(filename) );
423
424         PCXfile = cfopen( filename , "rb" );
425         if ( !PCXfile ){
426                 return PCX_ERROR_OPENING;
427         }
428
429         // read 128 char PCX header
430         if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1)        {
431                 cfclose( PCXfile );
432                 return PCX_ERROR_NO_HEADER;
433         }
434
435         header.Xmin = INTEL_SHORT( header.Xmin );
436         header.Ymin = INTEL_SHORT( header.Ymin );
437         header.Xmax = INTEL_SHORT( header.Xmax );
438         header.Ymax = INTEL_SHORT( header.Ymax );
439         header.Hdpi = INTEL_SHORT( header.Hdpi );
440         header.Vdpi = INTEL_SHORT( header.Vdpi );
441
442         header.BytesPerLine = INTEL_SHORT( header.BytesPerLine );
443
444         // Is it a 256 color PCX file?
445         if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5))      {
446                 cfclose( PCXfile );
447                 return PCX_ERROR_WRONG_VERSION;
448         }
449
450         // Find the size of the image
451         xsize = header.Xmax - header.Xmin + 1;
452         ysize = header.Ymax - header.Ymin + 1;
453
454         // Read the extended palette at the end of PCX file
455         // Read in a character which should be 12 to be extended palette file
456
457         cfseek( PCXfile, -768, CF_SEEK_END );
458         cfread( palette, 3, 256, PCXfile );
459         cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
460         
461         buffer_size = 1024;
462         buffer_pos = 0;
463         
464 //      SDL_assert( buffer_size == 1024 );      // AL: removed to avoid optimized warning 'unreachable code'
465         buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
466
467         count = 0;
468
469         for (row=0; row<ysize;row++)      {
470                 pixdata = org_data;
471                 for (col=0; col<header.BytesPerLine;col++)     {
472                         if ( count == 0 )       {
473                                 data = buffer[buffer_pos++];
474                                 if ( buffer_pos == buffer_size )        {
475                                         buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
476                                         SDL_assert( buffer_size > 0 );
477                                         buffer_pos = 0;
478                                 }
479                                 if ((data & 0xC0) == 0xC0)     {
480                                         count = data & 0x3F;
481                                         data = buffer[buffer_pos++];
482                                         if ( buffer_pos == buffer_size )        {
483                                                 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
484                                                 SDL_assert( buffer_size > 0 );
485                                                 buffer_pos = 0;
486                                         }
487                                 } else {
488                                         count = 1;
489                                 }
490                         }
491                         // stuff the pixel
492                         if ( col < xsize ){                             
493                                 // stuff the pixel
494                                 // memcpy(pixdata, &data, 2);
495                                 *((ushort*)pixdata) = (ushort)data;
496
497                                 pixdata += 2;
498                         }
499                         count--;
500                 }
501
502                 org_data += (xsize * 2);
503         }
504         cfclose(PCXfile);
505         return PCX_ERROR_NONE;
506 }
507
508 int pcx_read_bitmap_16bpp_nondark( char * real_filename, ubyte *org_data )
509 {       
510         PCXHeader header;
511         CFILE * PCXfile;
512         int row, col, count, xsize, ysize;
513         ubyte data=0;
514         int buffer_size, buffer_pos;
515         ubyte buffer[1024];
516         ubyte *pixdata;
517         char filename[MAX_FILENAME_LEN];
518         ubyte palette[768];     
519         ushort bit_16;  
520         ubyte r, g, b, al;
521                 
522         SDL_strlcpy( filename, real_filename, SDL_arraysize(filename) );
523         char *p = SDL_strchr( filename, '.' );
524         if ( p ) *p = 0;
525         SDL_strlcat( filename, ".pcx", SDL_arraysize(filename) );
526
527         PCXfile = cfopen( filename , "rb" );
528         if ( !PCXfile ){
529                 return PCX_ERROR_OPENING;
530         }
531
532         // read 128 char PCX header
533         if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1)        {
534                 cfclose( PCXfile );
535                 return PCX_ERROR_NO_HEADER;
536         }
537         header.Xmin = INTEL_SHORT( header.Xmin );
538         header.Ymin = INTEL_SHORT( header.Ymin );
539         header.Xmax = INTEL_SHORT( header.Xmax );
540         header.Ymax = INTEL_SHORT( header.Ymax );
541         header.Hdpi = INTEL_SHORT( header.Hdpi );
542         header.Vdpi = INTEL_SHORT( header.Vdpi );
543         header.BytesPerLine = INTEL_SHORT( header.BytesPerLine );       
544
545         // Is it a 256 color PCX file?
546         if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5))      {
547                 cfclose( PCXfile );
548                 return PCX_ERROR_WRONG_VERSION;
549         }
550
551         // Find the size of the image
552         xsize = header.Xmax - header.Xmin + 1;
553         ysize = header.Ymax - header.Ymin + 1;
554
555         // Read the extended palette at the end of PCX file
556         // Read in a character which should be 12 to be extended palette file
557
558         cfseek( PCXfile, -768, CF_SEEK_END );
559         cfread( palette, 3, 256, PCXfile );
560         cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
561         
562         buffer_size = 1024;
563         buffer_pos = 0;
564         
565 //      SDL_assert( buffer_size == 1024 );      // AL: removed to avoid optimized warning 'unreachable code'
566         buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
567
568         count = 0;
569
570         for (row=0; row<ysize;row++)      {
571                 pixdata = org_data;
572                 for (col=0; col<header.BytesPerLine;col++)     {
573                         if ( count == 0 )       {
574                                 data = buffer[buffer_pos++];
575                                 if ( buffer_pos == buffer_size )        {
576                                         buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
577                                         SDL_assert( buffer_size > 0 );
578                                         buffer_pos = 0;
579                                 }
580                                 if ((data & 0xC0) == 0xC0)     {
581                                         count = data & 0x3F;
582                                         data = buffer[buffer_pos++];
583                                         if ( buffer_pos == buffer_size )        {
584                                                 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
585                                                 SDL_assert( buffer_size > 0 );
586                                                 buffer_pos = 0;
587                                         }
588                                 } else {
589                                         count = 1;
590                                 }
591                         }
592                         // stuff the pixel
593                         if ( col < xsize ){                             
594                                 // stuff the 24 bit value                               
595                                 r = palette[data*3];
596                                 g = palette[data*3 + 1];
597                                 b = palette[data*3 + 2];                                                        
598
599                                 // if this is a nondarkening texture                            
600                                 // if this color matches a nondarkening pixel color, set the alpha to high
601                                 al = 0;
602                                 if(palman_is_nondarkening(r, g, b)){
603                                         al = 255;
604                                 }
605
606                                 // set the pixel
607                                 bit_16 = 0;
608                                 bm_set_components((ubyte*)&bit_16, &r, &g, &b, &al);                                    
609                                 
610                                 // stuff the pixel
611                                 *((ushort*)pixdata) = bit_16;                           
612                                 pixdata += 2;
613                         }
614                         count--;
615                 }
616
617                 org_data += (xsize * 2);
618         }
619         cfclose(PCXfile);
620         return PCX_ERROR_NONE;
621 }
622
623 // subroutine for writing an encoded byte pair
624 // returns count of bytes written, 0 if error
625 int pcx_encode_byte(ubyte byt, ubyte cnt, FILE * fid)
626 {
627         if (cnt) {
628                 if ( (cnt==1) && (0xc0 != (0xc0 & byt)) )       {
629                         if(EOF == putc((int)byt, fid))
630                                 return 0;       // disk write error (probably full)
631                         return 1;
632                 } else {
633                         if(EOF == putc((int)0xC0 | cnt, fid))
634                                 return 0;       // disk write error
635                         if(EOF == putc((int)byt, fid))
636                                 return 0;       // disk write error
637                         return 2;
638                 }
639         }
640         return 0;
641 }
642
643 // returns number of bytes written into outBuff, 0 if failed
644 int pcx_encode_line(ubyte *inBuff, int inLen, FILE * fp)
645 {
646         ubyte this_ptr, last;
647
648         int srcIndex, i;
649         register int total;
650         register ubyte runCount;        // max single runlength is 63
651         total = 0;
652         last = *(inBuff);
653         runCount = 1;
654
655         for (srcIndex = 1; srcIndex < inLen; srcIndex++) {
656                 this_ptr = *(++inBuff);
657                 if (this_ptr == last)   {
658                         runCount++;                     // it encodes
659                         if (runCount == 63)     {
660                                 i = pcx_encode_byte(last, runCount, fp);
661                                 if(!i){
662                                         return(0);
663                                 }
664                                 total += i;
665                                 runCount = 0;
666                         }
667                 } else {        // this_ptr != last
668                         if (runCount)   {
669                                 i = pcx_encode_byte(last, runCount, fp);
670                                 if (!i){
671                                         return(0);
672                                 }
673                                 total += i;
674                         }
675                         last = this_ptr;
676                         runCount = 1;
677                 }
678         }
679
680         if (runCount)   {               // finish up
681                 i = pcx_encode_byte(last, runCount, fp);
682                 if (!i){
683                         return 0;
684                 }
685                 return total + i;
686         }
687         return total;
688 }
689
690
691 int pcx_write_bitmap( char * real_filename, int w, int h, ubyte ** row_ptrs, ubyte * palette )
692 {
693         int retval;
694         int i;
695         ubyte data;
696         PCXHeader header;
697         FILE * PCXfile;
698         char filename[MAX_FILENAME_LEN];
699                 
700         SDL_strlcpy( filename, real_filename, SDL_arraysize(filename) );
701         char *p = SDL_strchr( filename, '.' );
702         if ( p ) *p = 0;
703         SDL_strlcat( filename, ".pcx", SDL_arraysize(filename) );
704
705         memset( &header, 0, sizeof( PCXHeader ) );
706
707         header.Manufacturer = 10;
708         header.Encoding = 1;
709         header.Nplanes = 1;
710         header.BitsPerPixel = 8;
711         header.Version = 5;
712         header.Xmax = (short)(w-1);
713         header.Ymax = (short)(h-1);
714         header.Ymin = 0;
715         header.Xmin = 0;
716         header.BytesPerLine =(short)(w);
717
718         PCXfile = fopen( filename , "wb" );
719         if ( !PCXfile )
720                 return PCX_ERROR_OPENING;
721
722         if ( fwrite( &header, sizeof( PCXHeader ), 1, PCXfile ) != 1 )  {
723                 fclose( PCXfile );
724                 return PCX_ERROR_WRITING;
725         }
726
727         for (i=0; i<h; i++ )    {
728                 if (!pcx_encode_line( row_ptrs[i], w, PCXfile ))        {
729                         fclose( PCXfile );
730                         return PCX_ERROR_WRITING;
731                 }
732         }
733
734         // Mark an extended palette
735         data = 12;
736         if (fwrite( &data, 1, 1, PCXfile )!=1)  {
737                 fclose( PCXfile );
738                 return PCX_ERROR_WRITING;
739         }
740
741         // Write the extended palette
742 //      for (i=0; i<768; i++ )
743 //              palette[i] <<= 2;
744
745         retval = fwrite( palette, 768, 1, PCXfile );
746
747 //      for (i=0; i<768; i++ )
748 //              palette[i] >>= 2;
749
750         if (retval !=1) {
751                 fclose( PCXfile );
752                 return PCX_ERROR_WRITING;
753         }
754
755         fclose( PCXfile );
756         return PCX_ERROR_NONE;
757
758 }
759
760 //text for error messges
761 char pcx_error_messages[] = {
762         "No error.\0"
763         "Error opening file.\0"
764         "Couldn't read PCX header.\0"
765         "Unsupported PCX version.\0"
766         "Error reading data.\0"
767         "Couldn't find palette information.\0"
768         "Error writing data.\0"
769 };
770
771
772 //function to return pointer to error message
773 char *pcx_errormsg(int error_number)
774 {
775         char *p = pcx_error_messages;
776
777         while (error_number--) {
778
779                 if (!p) return NULL;
780
781                 p += strlen(p)+1;
782
783         }
784
785         return p;
786
787 }
788