2 * $Logfile: /Freespace2/code/PcxUtils/pcxutils.cpp $
7 * code to deal with pcx files
10 * Revision 1.1 2002/05/03 03:28:10 root
14 * 11 8/10/99 6:54p Dave
15 * Mad optimizations. Added paging to the nebula effect.
17 * 10 7/13/99 1:16p Dave
18 * 32 bit support. Whee!
20 * 9 2/05/99 12:52p Dave
21 * Fixed Glide nondarkening textures.
23 * 8 2/03/99 6:06p Dave
24 * Groundwork for FS2 PXO usertracker support. Gametracker support next.
26 * 7 2/03/99 11:44a Dave
27 * Fixed d3d transparent textures.
29 * 6 12/01/98 5:54p Dave
30 * Simplified the way pixel data is swizzled. Fixed tga bitmaps to work
31 * properly in D3D and Glide.
33 * 5 12/01/98 4:46p Dave
34 * Put in targa bitmap support (16 bit).
36 * 4 12/01/98 8:06a Dave
37 * Temporary checkin to fix some texture transparency problems in d3d.
39 * 3 11/30/98 1:07p Dave
40 * 16 bit conversion, first run.
42 * 2 10/07/98 10:53a Dave
45 * 1 10/07/98 10:50a Dave
47 * 16 1/19/98 11:37p Lawrance
48 * Fixing Optimization build warnings
50 * 15 9/09/97 3:39p Sandeep
51 * warning level 4 bugs
53 * 14 9/03/97 4:32p John
54 * changed bmpman to only accept ani and pcx's. made passing .pcx or .ani
55 * to bm_load functions not needed. Made bmpman keep track of palettes
56 * for bitmaps not mapped into game palettes.
58 * 13 7/20/97 6:59p Lawrance
59 * fixed bug that was writing out PCX files with an extra bogus line
61 * 12 6/05/97 6:07p John
64 * 11 6/05/97 3:59p John
65 * Fixed a bug in PCX reader
67 * 10 2/25/97 12:06p John
68 * fixed a pcx potential bug.
70 * 9 2/25/97 12:03p John
71 * fixed a pcx reading bug.
73 * 8 2/20/97 4:18p John
74 * fixed bug reading odd-width pcx files
76 * 7 11/26/96 9:28a Allender
77 * get palette info when getting pcx info
79 * 6 11/18/96 12:36p John
80 * Added code to dump screen to a PCX file.
82 * 5 11/13/96 4:51p Allender
83 * started overhaul of bitmap manager. bm_load no longer actually load
84 * the data, only the info for the bitmap. Locking the bitmap now forces
85 * load when no data present (or will if bpp changes)
95 /* PCX Header data type */
107 ubyte ColorMap[16][3];
114 // reads header information from the PCX file into the bitmap pointer
115 int pcx_read_header(char *real_filename, int *w, int *h, ubyte *pal )
119 char filename[MAX_FILENAME_LEN];
121 strcpy( filename, real_filename );
122 char *p = strchr( filename, '.' );
124 strcat( filename, ".pcx" );
126 PCXfile = cfopen( filename , "rb" );
128 return PCX_ERROR_OPENING;
130 // read 128 char PCX header
131 if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
133 return PCX_ERROR_NO_HEADER;
136 // Is it a 256 color PCX file?
137 if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
139 return PCX_ERROR_WRONG_VERSION;
142 if (w) *w = header.Xmax - header.Xmin + 1;
143 if (h) *h = header.Ymax - header.Ymin + 1;
146 cfseek( PCXfile, -768, CF_SEEK_END );
147 cfread( pal, 3, 256, PCXfile );
151 return PCX_ERROR_NONE;
154 // static ubyte Pcx_load[1024*768 + 768 + sizeof(PCXHeader)];
155 // int Pcx_load_offset = 0;
156 // int Pcx_load_size = 0;
158 // #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);
159 int pcx_read_bitmap_8bpp( char * real_filename, ubyte *org_data, ubyte *palette )
163 int row, col, count, xsize, ysize;
165 int buffer_size, buffer_pos;
168 char filename[MAX_FILENAME_LEN];
170 strcpy( filename, real_filename );
171 char *p = strchr( filename, '.' );
173 strcat( filename, ".pcx" );
175 PCXfile = cfopen( filename , "rb" );
177 return PCX_ERROR_OPENING;
179 // read 128 char PCX header
180 if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
182 return PCX_ERROR_NO_HEADER;
185 // Is it a 256 color PCX file?
186 if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
188 return PCX_ERROR_WRONG_VERSION;
191 // Find the size of the image
192 xsize = header.Xmax - header.Xmin + 1;
193 ysize = header.Ymax - header.Ymin + 1;
195 // Read the extended palette at the end of PCX file
196 // Read in a character which should be 12 to be extended palette file
198 cfseek( PCXfile, -768, CF_SEEK_END );
199 cfread( palette, 3, 256, PCXfile );
200 cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
205 // Assert( buffer_size == 1024 ); // AL: removed to avoid optimized warning 'unreachable code'
206 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
210 for (row=0; row<ysize;row++) {
212 for (col=0; col<header.BytesPerLine;col++) {
214 data = buffer[buffer_pos++];
215 if ( buffer_pos == buffer_size ) {
216 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
217 Assert( buffer_size > 0 );
220 if ((data & 0xC0) == 0xC0) {
222 data = buffer[buffer_pos++];
223 if ( buffer_pos == buffer_size ) {
224 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
225 Assert( buffer_size > 0 );
239 return PCX_ERROR_NONE;
242 int pcx_read_bitmap_16bpp( char * real_filename, ubyte *org_data )
246 int row, col, count, xsize, ysize;
248 int buffer_size, buffer_pos;
251 char filename[MAX_FILENAME_LEN];
256 strcpy( filename, real_filename );
257 char *p = strchr( filename, '.' );
259 strcat( filename, ".pcx" );
261 PCXfile = cfopen( filename , "rb" );
263 return PCX_ERROR_OPENING;
266 // read 128 char PCX header
267 if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
269 return PCX_ERROR_NO_HEADER;
272 // Is it a 256 color PCX file?
273 if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
275 return PCX_ERROR_WRONG_VERSION;
278 // Find the size of the image
279 xsize = header.Xmax - header.Xmin + 1;
280 ysize = header.Ymax - header.Ymin + 1;
282 // Read the extended palette at the end of PCX file
283 // Read in a character which should be 12 to be extended palette file
285 cfseek( PCXfile, -768, CF_SEEK_END );
286 cfread( palette, 3, 256, PCXfile );
287 cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
292 // Assert( buffer_size == 1024 ); // AL: removed to avoid optimized warning 'unreachable code'
293 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
297 for (row=0; row<ysize;row++) {
299 for (col=0; col<header.BytesPerLine;col++) {
301 data = buffer[buffer_pos++];
302 if ( buffer_pos == buffer_size ) {
303 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
304 Assert( buffer_size > 0 );
307 if ((data & 0xC0) == 0xC0) {
309 data = buffer[buffer_pos++];
310 if ( buffer_pos == buffer_size ) {
311 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
312 Assert( buffer_size > 0 );
321 // stuff the 24 bit value
323 g = palette[data*3 + 1];
324 b = palette[data*3 + 2];
329 // if the color matches the transparent color, make it so
331 if((0 == (int)palette[data*3]) && (255 == (int)palette[data*3+1]) && (0 == (int)palette[data*3+2])){
338 bm_set_components((ubyte*)&bit_16, &r, &g, &b, &al);
341 *((ushort*)pixdata) = bit_16;
347 org_data += (xsize * 2);
350 return PCX_ERROR_NONE;
353 int pcx_read_bitmap_16bpp_aabitmap( char * real_filename, ubyte *org_data )
357 int row, col, count, xsize, ysize;
359 int buffer_size, buffer_pos;
362 char filename[MAX_FILENAME_LEN];
365 strcpy( filename, real_filename );
366 char *p = strchr( filename, '.' );
369 strcat( filename, ".pcx" );
371 PCXfile = cfopen( filename , "rb" );
373 return PCX_ERROR_OPENING;
376 // read 128 char PCX header
377 if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
379 return PCX_ERROR_NO_HEADER;
382 // Is it a 256 color PCX file?
383 if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
385 return PCX_ERROR_WRONG_VERSION;
388 // Find the size of the image
389 xsize = header.Xmax - header.Xmin + 1;
390 ysize = header.Ymax - header.Ymin + 1;
392 // Read the extended palette at the end of PCX file
393 // Read in a character which should be 12 to be extended palette file
395 cfseek( PCXfile, -768, CF_SEEK_END );
396 cfread( palette, 3, 256, PCXfile );
397 cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
402 // Assert( buffer_size == 1024 ); // AL: removed to avoid optimized warning 'unreachable code'
403 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
407 for (row=0; row<ysize;row++) {
409 for (col=0; col<header.BytesPerLine;col++) {
411 data = buffer[buffer_pos++];
412 if ( buffer_pos == buffer_size ) {
413 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
414 Assert( buffer_size > 0 );
417 if ((data & 0xC0) == 0xC0) {
419 data = buffer[buffer_pos++];
420 if ( buffer_pos == buffer_size ) {
421 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
422 Assert( buffer_size > 0 );
432 // memcpy(pixdata, &data, 2);
433 *((ushort*)pixdata) = (ushort)data;
440 org_data += (xsize * 2);
443 return PCX_ERROR_NONE;
446 int pcx_read_bitmap_16bpp_nondark( char * real_filename, ubyte *org_data )
450 int row, col, count, xsize, ysize;
452 int buffer_size, buffer_pos;
455 char filename[MAX_FILENAME_LEN];
460 strcpy( filename, real_filename );
461 char *p = strchr( filename, '.' );
463 strcat( filename, ".pcx" );
465 PCXfile = cfopen( filename , "rb" );
467 return PCX_ERROR_OPENING;
470 // read 128 char PCX header
471 if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
473 return PCX_ERROR_NO_HEADER;
476 // Is it a 256 color PCX file?
477 if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
479 return PCX_ERROR_WRONG_VERSION;
482 // Find the size of the image
483 xsize = header.Xmax - header.Xmin + 1;
484 ysize = header.Ymax - header.Ymin + 1;
486 // Read the extended palette at the end of PCX file
487 // Read in a character which should be 12 to be extended palette file
489 cfseek( PCXfile, -768, CF_SEEK_END );
490 cfread( palette, 3, 256, PCXfile );
491 cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
496 // Assert( buffer_size == 1024 ); // AL: removed to avoid optimized warning 'unreachable code'
497 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
501 for (row=0; row<ysize;row++) {
503 for (col=0; col<header.BytesPerLine;col++) {
505 data = buffer[buffer_pos++];
506 if ( buffer_pos == buffer_size ) {
507 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
508 Assert( buffer_size > 0 );
511 if ((data & 0xC0) == 0xC0) {
513 data = buffer[buffer_pos++];
514 if ( buffer_pos == buffer_size ) {
515 buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
516 Assert( buffer_size > 0 );
525 // stuff the 24 bit value
527 g = palette[data*3 + 1];
528 b = palette[data*3 + 2];
530 // if this is a nondarkening texture
531 // if this color matches a nondarkening pixel color, set the alpha to high
533 if(palman_is_nondarkening(r, g, b)){
539 bm_set_components((ubyte*)&bit_16, &r, &g, &b, &al);
542 *((ushort*)pixdata) = bit_16;
548 org_data += (xsize * 2);
551 return PCX_ERROR_NONE;
554 // subroutine for writing an encoded byte pair
555 // returns count of bytes written, 0 if error
556 int pcx_encode_byte(ubyte byt, ubyte cnt, FILE * fid)
559 if ( (cnt==1) && (0xc0 != (0xc0 & byt)) ) {
560 if(EOF == putc((int)byt, fid))
561 return 0; // disk write error (probably full)
564 if(EOF == putc((int)0xC0 | cnt, fid))
565 return 0; // disk write error
566 if(EOF == putc((int)byt, fid))
567 return 0; // disk write error
574 // returns number of bytes written into outBuff, 0 if failed
575 int pcx_encode_line(ubyte *inBuff, int inLen, FILE * fp)
577 ubyte this_ptr, last;
581 register ubyte runCount; // max single runlength is 63
586 for (srcIndex = 1; srcIndex < inLen; srcIndex++) {
587 this_ptr = *(++inBuff);
588 if (this_ptr == last) {
589 runCount++; // it encodes
590 if (runCount == 63) {
591 i = pcx_encode_byte(last, runCount, fp);
598 } else { // this_ptr != last
600 i = pcx_encode_byte(last, runCount, fp);
611 if (runCount) { // finish up
612 i = pcx_encode_byte(last, runCount, fp);
622 int pcx_write_bitmap( char * real_filename, int w, int h, ubyte ** row_ptrs, ubyte * palette )
629 char filename[MAX_FILENAME_LEN];
631 strcpy( filename, real_filename );
632 char *p = strchr( filename, '.' );
634 strcat( filename, ".pcx" );
636 memset( &header, 0, sizeof( PCXHeader ) );
638 header.Manufacturer = 10;
641 header.BitsPerPixel = 8;
643 header.Xmax = (short)(w-1);
644 header.Ymax = (short)(h-1);
647 header.BytesPerLine =(short)(w);
649 PCXfile = fopen( filename , "wb" );
651 return PCX_ERROR_OPENING;
653 if ( fwrite( &header, sizeof( PCXHeader ), 1, PCXfile ) != 1 ) {
655 return PCX_ERROR_WRITING;
658 for (i=0; i<h; i++ ) {
659 if (!pcx_encode_line( row_ptrs[i], w, PCXfile )) {
661 return PCX_ERROR_WRITING;
665 // Mark an extended palette
667 if (fwrite( &data, 1, 1, PCXfile )!=1) {
669 return PCX_ERROR_WRITING;
672 // Write the extended palette
673 // for (i=0; i<768; i++ )
676 retval = fwrite( palette, 768, 1, PCXfile );
678 // for (i=0; i<768; i++ )
683 return PCX_ERROR_WRITING;
687 return PCX_ERROR_NONE;
691 //text for error messges
692 char pcx_error_messages[] = {
694 "Error opening file.\0"
695 "Couldn't read PCX header.\0"
696 "Unsupported PCX version.\0"
697 "Error reading data.\0"
698 "Couldn't find palette information.\0"
699 "Error writing data.\0"
703 //function to return pointer to error message
704 char *pcx_errormsg(int error_number)
706 char *p = pcx_error_messages;
708 while (error_number--) {