PageRenderTime 156ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/code/pcxutils/pcxutils.cpp

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