FS2_Open
Open source remastering of the Freespace 2 engine
pcxutils.cpp
Go to the documentation of this file.
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 the
6  * source.
7  *
8 */
9 
10 
11 
12 #include "cfile/cfile.h"
13 #include "pcxutils/pcxutils.h"
14 #include "palman/palman.h"
15 #include "bmpman/bmpman.h"
16 
17 
18 
19 
20 /* PCX Header data type */
21 typedef struct {
26  short Xmin;
27  short Ymin;
28  short Xmax;
29  short Ymax;
30  short Hdpi;
31  short Vdpi;
32  ubyte ColorMap[16][3];
35  short BytesPerLine;
36  ubyte filler[60];
37 } PCXHeader;
38 
39 // reads header information from the PCX file into the bitmap pointer
40 int pcx_read_header(const char *real_filename, CFILE *img_cfp, int *w, int *h, int *bpp, ubyte *pal )
41 {
43  CFILE * PCXfile;
45  int i, j;
46 
47  if (img_cfp == NULL) {
48  strcpy_s( filename, real_filename );
49  char *p = strchr( filename, '.' );
50  if ( p ) *p = 0;
51  strcat_s( filename, ".pcx" );
52 
53  PCXfile = cfopen( filename , "rb" );
54  if ( !PCXfile )
55  return PCX_ERROR_OPENING;
56  } else {
57  PCXfile = img_cfp;
58  }
59 
60  // read 128 char PCX header
61  if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
62  if (img_cfp == NULL)
63  cfclose( PCXfile );
64  return PCX_ERROR_NO_HEADER;
65  }
66 
67  header.Xmin = INTEL_SHORT( header.Xmin ); //-V570
68  header.Ymin = INTEL_SHORT( header.Ymin ); //-V570
69  header.Xmax = INTEL_SHORT( header.Xmax ); //-V570
70  header.Ymax = INTEL_SHORT( header.Ymax ); //-V570
71  header.Hdpi = INTEL_SHORT( header.Hdpi ); //-V570
72  header.Vdpi = INTEL_SHORT( header.Vdpi ); //-V570
73 
74  for (i=0; i<16; i++ ){
75  for (j=0; j<3; j++){
76  header.ColorMap[i][j] = INTEL_INT( header.ColorMap[i][j] ); //-V570
77  }
78  }
79 
80  header.BytesPerLine = INTEL_SHORT( header.BytesPerLine ); //-V570
81 
82  for (i=0; i<60; i++ ){
83  header.filler[i] = INTEL_INT( header.filler[i] ); //-V570
84  }
85 
86  // Is it a 256 color PCX file?
87  if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
88  if (img_cfp == NULL)
89  cfclose( PCXfile );
91  }
92 
93  if (w) *w = header.Xmax - header.Xmin + 1;
94  if (h) *h = header.Ymax - header.Ymin + 1;
95  if (bpp) *bpp = header.BitsPerPixel;
96 
97  if ( pal ) {
98  cfseek( PCXfile, -768, CF_SEEK_END );
99  cfread( pal, 3, 256, PCXfile );
100  }
101 
102  if (img_cfp == NULL)
103  cfclose(PCXfile);
104 
105  return PCX_ERROR_NONE;
106 }
107 
108 // static ubyte Pcx_load[1024*768 + 768 + sizeof(PCXHeader)];
109 // int Pcx_load_offset = 0;
110 // int Pcx_load_size = 0;
111 /*
112 // #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);
113 int pcx_read_bitmap_8bpp( char * real_filename, ubyte *org_data, ubyte *palette )
114 {
115  PCXHeader header;
116  CFILE * PCXfile;
117  int row, col, count, xsize, ysize;
118  ubyte data=0;
119  int buffer_size, buffer_pos;
120  ubyte buffer[1024];
121  ubyte *pixdata;
122  char filename[MAX_FILENAME_LEN];
123 
124  strcpy_s( filename, real_filename );
125  char *p = strchr( filename, '.' );
126  if ( p ) *p = 0;
127  strcat_s( filename, ".pcx" );
128 
129  PCXfile = cfopen( filename , "rb" );
130  if ( !PCXfile )
131  return PCX_ERROR_OPENING;
132 
133  // read 128 char PCX header
134  if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
135  cfclose( PCXfile );
136  return PCX_ERROR_NO_HEADER;
137  }
138 
139  header.Xmin = INTEL_SHORT( header.Xmin );
140  header.Ymin = INTEL_SHORT( header.Ymin );
141  header.Xmax = INTEL_SHORT( header.Xmax );
142  header.Ymax = INTEL_SHORT( header.Ymax );
143  header.Hdpi = INTEL_SHORT( header.Hdpi );
144  header.Vdpi = INTEL_SHORT( header.Vdpi );
145  header.BytesPerLine = INTEL_SHORT( header.BytesPerLine );
146 
147  // Is it a 256 color PCX file?
148  if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
149  cfclose( PCXfile );
150  return PCX_ERROR_WRONG_VERSION;
151  }
152 
153  // Find the size of the image
154  xsize = header.Xmax - header.Xmin + 1;
155  ysize = header.Ymax - header.Ymin + 1;
156 
157  // Read the extended palette at the end of PCX file
158  // Read in a character which should be 12 to be extended palette file
159 
160  cfseek( PCXfile, -768, CF_SEEK_END );
161  cfread( palette, 3, 256, PCXfile );
162 
163  for ( int i=0; i<256; i++ ){ //tigital
164  palette[i] = INTEL_INT( palette[i] );
165  }
166 
167  cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
168 
169  buffer_size = 1024;
170  buffer_pos = 0;
171 
172  buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
173 
174  count = 0;
175 
176  for (row=0; row<ysize;row++) {
177  pixdata = org_data;
178  for (col=0; col<header.BytesPerLine;col++) {
179  if ( count == 0 ) {
180  data = buffer[buffer_pos++];
181  if ( buffer_pos == buffer_size ) {
182  buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
183  Assert( buffer_size > 0 );
184  buffer_pos = 0;
185  }
186  if ((data & 0xC0) == 0xC0) {
187  count = data & 0x3F;
188  data = buffer[buffer_pos++];
189  if ( buffer_pos == buffer_size ) {
190  buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
191  Assert( buffer_size > 0 );
192  buffer_pos = 0;
193  }
194  } else {
195  count = 1;
196  }
197  }
198  if ( col < xsize )
199  *pixdata++ = data;
200  count--;
201  }
202  org_data += xsize;
203  }
204  cfclose(PCXfile);
205 
206  return PCX_ERROR_NONE;
207 }
208 */
209 
210 #if BYTE_ORDER == BIG_ENDIAN
211 typedef struct { ubyte a, r, g, b; } COLOR32;
212 #else
213 typedef struct { ubyte b, g, r, a; } COLOR32;
214 #endif
215 
216 //int pcx_read_bitmap_16bpp( char * real_filename, ubyte *org_data, ubyte bpp, int aabitmap, int nondark )
217 int pcx_read_bitmap( const char * real_filename, ubyte *org_data, ubyte *pal, int byte_size, int aabitmap, int nondark, int cf_type )
218 {
220  CFILE * PCXfile;
221  int row, col, count, xsize, ysize;
222  ubyte data=0;
223  int buffer_size, buffer_pos;
224  ubyte buffer[1024];
225  ubyte *pixdata;
227  ubyte palette[768];
228  ushort bit_16;
229  COLOR32 bit_32;
230  ubyte r, g, b, al;
231 
232  strcpy_s( filename, real_filename );
233  char *p = strchr( filename, '.' );
234  if ( p ) *p = 0;
235  strcat_s( filename, ".pcx" );
236 
237 
238  PCXfile = cfopen( filename , "rb", CFILE_NORMAL, cf_type );
239  if ( !PCXfile ){
240 
241  return PCX_ERROR_OPENING;
242  }
243 
244  // read 128 char PCX header
245  if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
246  cfclose( PCXfile );
247 
248  return PCX_ERROR_NO_HEADER;
249  }
250 
251  header.Xmin = INTEL_SHORT( header.Xmin ); //-V570
252  header.Ymin = INTEL_SHORT( header.Ymin ); //-V570
253  header.Xmax = INTEL_SHORT( header.Xmax ); //-V570
254  header.Ymax = INTEL_SHORT( header.Ymax ); //-V570
255  header.Hdpi = INTEL_SHORT( header.Hdpi ); //-V570
256  header.Vdpi = INTEL_SHORT( header.Vdpi ); //-V570
257  header.BytesPerLine = INTEL_SHORT( header.BytesPerLine ); //-V570
258 
259  // Is it a 256 color PCX file?
260  if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
261  cfclose( PCXfile );
262 
264  }
265 
266 
267  // Find the size of the image
268  xsize = header.Xmax - header.Xmin + 1;
269  ysize = header.Ymax - header.Ymin + 1;
270 
271  // Read the extended palette at the end of PCX file
272  // Read in a character which should be 12 to be extended palette file
273 
274  cfseek( PCXfile, -768, CF_SEEK_END );
275  cfread( palette, 1, (3 * 256), PCXfile );
276  cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
277 
278  buffer_size = 1024;
279  buffer_pos = 0;
280 
281 // Assert( buffer_size == 1024 ); // AL: removed to avoid optimized warning 'unreachable code'
282 
283  buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
284 
285  count = 0;
286 
287  for (row=0; row<ysize;row++) {
288 
289  pixdata = org_data;
290  for (col=0; col<header.BytesPerLine;col++) {
291  if ( count == 0 ) {
292  data = buffer[buffer_pos++];
293  if ( buffer_pos == buffer_size ) {
294  buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
295  Assert( buffer_size > 0 );
296  buffer_pos = 0;
297  }
298  if ((data & 0xC0) == 0xC0) {
299  count = data & 0x3F;
300  data = buffer[buffer_pos++];
301  if ( buffer_pos == buffer_size ) {
302  buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
303  Assert( buffer_size > 0 );
304  buffer_pos = 0;
305  }
306  } else {
307  count = 1;
308  }
309  }
310  // stuff the pixel
311  if ( col < xsize ) {
312  // 8-bit PCX reads
313  if ( byte_size == 1 ) {
314  *pixdata++ = data;
315  } else {
316  // 16-bit AABITMAP reads
317  if ( (byte_size == 2) && aabitmap ) {
318  // stuff the pixel
319  // memcpy(pixdata, &data, 2);
320  *((ushort*)pixdata) = (ushort)data;
321  } else {
322  // stuff the 24 bit value
323  r = palette[data*3];
324  g = palette[data*3 + 1];
325  b = palette[data*3 + 2];
326 
327  // clear the pixel
328  bit_16 = 0;
329  memset(&bit_32, 0, sizeof(COLOR32));
330 
331  // 16-bit non-darkening reads
332  if ( (byte_size == 2) && nondark ) {
333  al = 0;
334  if (palman_is_nondarkening(r, g, b)) {
335  al = 255;
336  }
337  } else {
338  // if the color matches the transparent color, make it so
339  al = 255;
340 
341  if ( (0 == (int)palette[data*3]) && (255 == (int)palette[data*3+1]) && (0 == (int)palette[data*3+2]) ) {
342  r = b = 0;
343  g = (byte_size == 4) ? 0 : 255;
344  al = 0;
345  }
346  }
347 
348  // normal 16-bit reads
349  if ( byte_size == 2 ) {
350  // stuff the color
351  bm_set_components((ubyte*)&bit_16, &r, &g, &b, &al);
352 
353  // stuff the pixel
354  *((ushort*)pixdata) = bit_16;
355  }
356  // normal 32-bit reads
357  else if ( byte_size == 4 ) {
358  if ( /*(r == 0) && (b == 0) && (g == 255) && (al == 0)*/ 0 ) {
359  memset(&bit_32, 0, sizeof(COLOR32));
360  } else {
361  bit_32.r = r;
362  bit_32.g = g;
363  bit_32.b = b;
364  bit_32.a = al;
365  }
366 
367  // stuff the pixel
368  *((COLOR32*)pixdata) = bit_32;
369  }
370  }
371 
372  pixdata += byte_size;
373  }
374  }
375 
376  count--;
377  }
378 
379  org_data += (xsize * byte_size);
380  }
381 
382  cfclose(PCXfile);
383 
384  return PCX_ERROR_NONE;
385 }
386 
387 // subroutine for writing an encoded byte pair
388 // returns count of bytes written, 0 if error
389 int pcx_encode_byte(ubyte byt, ubyte cnt, FILE * fid)
390 {
391  if (cnt) {
392  if ( (cnt==1) && (0xc0 != (0xc0 & byt)) ) {
393  if(EOF == putc((int)byt, fid))
394  return 0; // disk write error (probably full)
395  return 1;
396  } else {
397  if(EOF == putc((int)0xC0 | cnt, fid))
398  return 0; // disk write error
399  if(EOF == putc((int)byt, fid))
400  return 0; // disk write error
401  return 2;
402  }
403  }
404  return 0;
405 }
406 
407 // returns number of bytes written into outBuff, 0 if failed
408 int pcx_encode_line(ubyte *inBuff, int inLen, FILE * fp)
409 {
410  ubyte this_ptr, last;
411 
412  int srcIndex, i;
413  int total;
414  ubyte runCount; // max single runlength is 63
415  total = 0;
416  last = *(inBuff);
417  runCount = 1;
418 
419  for (srcIndex = 1; srcIndex < inLen; srcIndex++) {
420  this_ptr = *(++inBuff);
421  if (this_ptr == last) {
422  runCount++; // it encodes
423  if (runCount == 63) {
424  i = pcx_encode_byte(last, runCount, fp);
425  if(!i){
426  return(0);
427  }
428  total += i;
429  runCount = 0;
430  }
431  } else { // this_ptr != last
432  if (runCount) {
433  i = pcx_encode_byte(last, runCount, fp);
434  if (!i){
435  return(0);
436  }
437  total += i;
438  }
439  last = this_ptr;
440  runCount = 1;
441  }
442  }
443 
444  if (runCount) { // finish up
445  i = pcx_encode_byte(last, runCount, fp);
446  if (!i){
447  return 0;
448  }
449  return total + i;
450  }
451  return total;
452 }
453 
454 
455 int pcx_write_bitmap( const char * real_filename, int w, int h, ubyte ** row_ptrs, ubyte * palette )
456 {
457  int retval;
458  int i;
459  ubyte data;
461  FILE * PCXfile;
463 
464  strcpy_s( filename, real_filename );
465  char *p = strchr( filename, '.' );
466  if ( p ) *p = 0;
467  strcat_s( filename, ".pcx" );
468 
469  memset( &header, 0, sizeof( PCXHeader ) );
470 
471  header.Manufacturer = 10;
472  header.Encoding = 1;
473  header.Nplanes = 1;
474  header.BitsPerPixel = 8;
475  header.Version = 5;
476  header.Xmax = (short)(w-1);
477  header.Ymax = (short)(h-1);
478  header.Ymin = 0;
479  header.Xmin = 0;
480  header.BytesPerLine =(short)(w);
481 
482  PCXfile = fopen( filename , "wb" );
483  if ( !PCXfile )
484  return PCX_ERROR_OPENING;
485 
486  if ( fwrite( &header, sizeof( PCXHeader ), 1, PCXfile ) != 1 ) {
487  fclose( PCXfile );
488  return PCX_ERROR_WRITING;
489  }
490 
491  for (i=0; i<h; i++ ) {
492  if (!pcx_encode_line( row_ptrs[i], w, PCXfile )) {
493  fclose( PCXfile );
494  return PCX_ERROR_WRITING;
495  }
496  }
497 
498  // Mark an extended palette
499  data = 12;
500  if (fwrite( &data, 1, 1, PCXfile )!=1) {
501  fclose( PCXfile );
502  return PCX_ERROR_WRITING;
503  }
504 
505  // Write the extended palette
506 // for (i=0; i<768; i++ )
507 // palette[i] <<= 2;
508 
509  retval = fwrite( palette, 768, 1, PCXfile );
510 
511 // for (i=0; i<768; i++ )
512 // palette[i] >>= 2;
513 
514  if (retval !=1) {
515  fclose( PCXfile );
516  return PCX_ERROR_WRITING;
517  }
518 
519  fclose( PCXfile );
520  return PCX_ERROR_NONE;
521 
522 }
523 
524 //text for error messges
526  "No error.\0"
527  "Error opening file.\0"
528  "Couldn't read PCX header.\0"
529  "Unsupported PCX version.\0"
530  "Error reading data.\0"
531  "Couldn't find palette information.\0"
532  "Error writing data.\0"
533 };
534 
535 
536 //function to return pointer to error message
537 char *pcx_errormsg(int error_number)
538 {
539  char *p = pcx_error_messages;
540 
541  while (error_number--) {
542 
543  if (!p) return NULL;
544 
545  p += strlen(p)+1;
546 
547  }
548 
549  return p;
550 
551 }
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
#define CFILE_NORMAL
Definition: cfile.h:89
int i
Definition: multi_pxo.cpp:466
int pcx_read_bitmap(const char *real_filename, ubyte *org_data, ubyte *pal, int byte_size, int aabitmap, int nondark, int cf_type)
Definition: pcxutils.cpp:217
short Ymin
Definition: pcxutils.cpp:27
GLfloat GLfloat GLfloat GLfloat h
Definition: Glext.h:7280
ubyte Nplanes
Definition: pcxutils.cpp:34
ubyte Version
Definition: pcxutils.cpp:23
struct header header
int cfread(void *buf, int elsize, int nelem, CFILE *fp)
ubyte Manufacturer
Definition: pcxutils.cpp:22
char pcx_error_messages[]
Definition: pcxutils.cpp:525
Assert(pm!=NULL)
#define PCX_ERROR_WRONG_VERSION
Definition: pcxutils.h:28
#define INTEL_SHORT(x)
Definition: pstypes.h:389
#define PCX_ERROR_NONE
Definition: pcxutils.h:25
Definition: cfile.h:28
#define CF_SEEK_SET
Definition: cfile.h:24
short Hdpi
Definition: pcxutils.cpp:30
#define PCX_ERROR_WRITING
Definition: pcxutils.h:31
ubyte a
Definition: pcxutils.cpp:211
ubyte Reserved
Definition: pcxutils.cpp:33
GLenum GLenum GLvoid * row
Definition: Glext.h:5241
short Ymax
Definition: pcxutils.cpp:29
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
void(* bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a)
Functional pointer that references any of the bm_set_components functions.
Definition: bmpman.cpp:76
GLboolean GLboolean g
Definition: Glext.h:5781
#define cfopen(...)
Definition: cfile.h:134
char * pcx_errormsg(int error_number)
Definition: pcxutils.cpp:537
#define CF_SEEK_END
Definition: cfile.h:26
GLboolean GLboolean GLboolean GLboolean a
Definition: Glext.h:5781
char * filename
ubyte b
Definition: pcxutils.cpp:211
#define PCX_ERROR_OPENING
Definition: pcxutils.h:26
GLuint buffer
Definition: Glext.h:5492
short Xmin
Definition: pcxutils.cpp:26
int pcx_read_header(const char *real_filename, CFILE *img_cfp, int *w, int *h, int *bpp, ubyte *pal)
Definition: pcxutils.cpp:40
cfbp fp
Definition: cfile.cpp:1065
ubyte ColorMap[16][3]
Definition: pcxutils.cpp:32
ubyte g
Definition: pcxutils.cpp:211
unsigned char ubyte
Definition: pstypes.h:62
ubyte BitsPerPixel
Definition: pcxutils.cpp:25
#define INTEL_INT(x)
Definition: pstypes.h:388
int pcx_encode_line(ubyte *inBuff, int inLen, FILE *fp)
Definition: pcxutils.cpp:408
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
short Xmax
Definition: pcxutils.cpp:28
int pcx_encode_byte(ubyte byt, ubyte cnt, FILE *fid)
Definition: pcxutils.cpp:389
#define strcat_s(...)
Definition: safe_strings.h:68
ubyte filler[60]
Definition: pcxutils.cpp:36
GLubyte GLubyte GLubyte GLubyte w
Definition: Glext.h:5679
ubyte Encoding
Definition: pcxutils.cpp:24
unsigned short ushort
Definition: pstypes.h:63
GLfloat GLfloat p
Definition: Glext.h:8373
int palman_is_nondarkening(int r, int g, int b)
Definition: palman.cpp:53
GLenum GLsizei GLenum GLenum const GLvoid * data
Definition: Gl.h:1509
ubyte r
Definition: pcxutils.cpp:211
GLint GLsizei count
Definition: Gl.h:1491
int cfclose(CFILE *cfile)
Definition: cfile.cpp:895
short Vdpi
Definition: pcxutils.cpp:31
int pcx_write_bitmap(const char *real_filename, int w, int h, ubyte **row_ptrs, ubyte *palette)
Definition: pcxutils.cpp:455
short BytesPerLine
Definition: pcxutils.cpp:35
#define PCX_ERROR_NO_HEADER
Definition: pcxutils.h:27
#define strcpy_s(...)
Definition: safe_strings.h:67
int cfseek(CFILE *fp, int offset, int where)