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 <string.h>
13
14 #include "globalincs/pstypes.h"
15 #include "tgautils/tgautils.h"
16 #include "cfile/cfile.h"
17 #include "bmpman/bmpman.h"
18 #include "palman/palman.h"
19 #include "graphics/2d.h"
20 #include "cmdline/cmdline.h"
21
22 // -----------------
23 //
24 // Defines
25 //
26 // -----------------
27
28 const char *Xfile_ID = "TRUEVISION-XFILE.";
29
30 #define TARGA_FOOTER_SIZE 26 // using sizeof(targa_footer) doesn't work unless we
31 // pack the struct and I don't want to do that :)
32
33 #define MAX_TARGA_RUN_LENGTH_PACKET 128
34 #define TARGA_HEADER_LENGTH 18
35 #define ULORIGIN (header.image_descriptor & 0x20)
36
37 // -----------------
38 //
39 // Structures
40 //
41 // -----------------
42
43 typedef struct targa_header {
44 short xoffset;
45 short yoffset;
46 short width;
47 short height;
48 short cmap_start;
49 short cmap_length;
50 ubyte id_length;
51 ubyte color_map_type;
52 ubyte image_type;
53 ubyte cmap_depth;
54 ubyte pixel_depth;
55 ubyte image_descriptor;
56 } targa_header;
57
58 typedef struct targa_footer {
59 uint ext_offset; // file offset to extension area (we ignore it)
60 uint dev_offset; // file offset to developer area (we also ignore this)
61 char sig_string[18]; // check to see if this is new TGA format, string should be value of Xfile_ID
62 } targa_footer;
63
64 // -----------------
65 //
66 // Internal Functions
67 //
68 // -----------------
69
70
71 // copy from one pixel buffer to another
72 //
73 // to - pointer to dest. buffet
74 // from - pointer to source buffer
75 // pixels - number of pixels to copy
76 // fromsize - source pixel size
77 // tosize - dest. pixel size
78 //
79 // returns - number of pixels copied to destination
80 //
targa_copy_data(char * to,char * from,int pixels,int fromsize,int tosize)81 static int targa_copy_data(char *to, char *from, int pixels, int fromsize, int tosize)
82 {
83 if ( (fromsize == 2) && (tosize==2) ) {
84 // Flip the alpha bit on 1555 format
85 ushort *src, *dst;
86
87 src = (ushort *)from;
88 dst = (ushort *)from;
89 for (int i=0; i<pixels; i++ ) {
90 *dst++ = (ushort)((*src++) ^ 0x8000); // Flip the transparency bit
91 }
92 return tosize*pixels;
93 } else if ( (fromsize == 2) && (tosize == 3) ) {
94 ushort *src;
95
96 src = (ushort *)from;
97 for (int i=0; i<pixels; i++ ) {
98 ushort pixel = *src++;
99
100 *to++ = (ubyte)((pixel & 0x1f) * 8);
101 *to++ = (ubyte)(((pixel >> 5) & 63) * 4);
102 *to++ = (ubyte)(((pixel >> 11) & 0x1f) * 8);
103 }
104 return tosize*pixels;
105 } else {
106 Assert(fromsize == tosize);
107 memcpy(to, from, pixels * fromsize);
108 return tosize*pixels;
109 }
110 }
111
112 // targa_pixels_equal -- Test if two pixels are identical
113 //
114 // pix1 - first pixel data
115 // pix2 - second pixel data
116 // pixbytes - number of bytes per pixel
117 //
118 // returns - 0 if No Match, else 1 if Match
targa_pixels_equal(char * pix1,char * pix2,int pixbytes)119 static int targa_pixels_equal(char *pix1, char *pix2, int pixbytes)
120 {
121 do {
122 if ( *pix1++ != *pix2++ ) {
123 return 0;
124 }
125 } while ( --pixbytes > 0 );
126
127 return 1;
128 }
129
130 // Perform targa RLE on the input data
131 //
132 // out - Buffer to write it out to
133 // in - Buffer to compress
134 // outsize - Number of bytes in output buffer
135 // pixsize - Number of bytes in input pixel
136 // bytecount - Number of bytes input
137 //
138 // returns - size of compressed data
139 //
targa_compress(char * out,char * in,int outsize,int pixsize,int bytecount)140 int targa_compress(char *out, char *in, int outsize, int pixsize, int bytecount)
141 {
142 int pixcount; // number of pixels in the current packet
143 char *inputpixel=NULL; // current input pixel position
144 char *matchpixel=NULL; // pixel value to match for a run
145 char *flagbyte=NULL; // location of last flag byte to set
146 int rlcount; // current count in r.l. string
147 int rlthresh; // minimum valid run length
148 char *copyloc; // location to begin copying at
149
150 // set the threshold -- the minimum valid run length
151
152 if (outsize == 1) {
153 rlthresh = 2; // for 8bpp, require a 2 pixel span before rle'ing
154 } else {
155 rlthresh = 1;
156 }
157
158 // set the first pixel up
159
160 flagbyte = out; // place to put next flag if run
161 inputpixel = in;
162 pixcount = 1;
163 rlcount = 0;
164 copyloc = (char *)0;
165
166 // loop till data processing complete
167 do {
168
169 // if we have accumulated a 128-byte packet, process it
170 if ( pixcount == 129 ) {
171 *flagbyte = 127;
172
173 // set the run flag if this is a run
174
175 if ( rlcount >= rlthresh ) {
176 *flagbyte |= 0x80;
177 pixcount = 2;
178 }
179
180 // copy the data into place
181 ++flagbyte;
182 flagbyte += targa_copy_data(flagbyte, copyloc, pixcount-1, pixsize, outsize);
183 pixcount = 1;
184
185 // set up for next packet
186 continue;
187 }
188
189 // if zeroth byte, handle as special case
190 if ( pixcount == 1 ) {
191 rlcount = 0;
192 copyloc = inputpixel; /* point to 1st guy in packet */
193 matchpixel = inputpixel; /* set pointer to pix to match */
194 pixcount = 2;
195 inputpixel += pixsize;
196 continue;
197 }
198
199 // assembling a packet -- look at next pixel
200
201 // current pixel == match pixel?
202 if ( targa_pixels_equal(inputpixel, matchpixel, outsize) ) {
203
204 // establishing a run of enough length to
205 // save space by doing it
206 // -- write the non-run length packet
207 // -- start run-length packet
208
209 if ( ++rlcount == rlthresh ) {
210
211 // close a non-run packet
212
213 if ( pixcount > (rlcount+1) ) {
214 // write out length and do not set run flag
215
216 *flagbyte++ = (char)(pixcount - 2 - rlthresh);
217
218 flagbyte += targa_copy_data(flagbyte, copyloc, (pixcount-1-rlcount), pixsize, outsize);
219
220 copyloc = inputpixel;
221 pixcount = rlcount + 1;
222 }
223 }
224 } else {
225
226 // no match -- either break a run or continue without one
227 // if a run exists break it:
228 // write the bytes in the string (outsize+1)
229 // start the next string
230
231 if ( rlcount >= rlthresh ) {
232
233 *flagbyte++ = (char)(0x80 | rlcount);
234 flagbyte += targa_copy_data(flagbyte, copyloc, 1, pixsize, outsize);
235 pixcount = 1;
236 continue;
237 } else {
238
239 // not a match and currently not a run
240 // - save the current pixel
241 // - reset the run-length flag
242 rlcount = 0;
243 matchpixel = inputpixel;
244 }
245 }
246 pixcount++;
247 inputpixel += pixsize;
248 } while ( inputpixel < (in + bytecount));
249
250 // quit this buffer without loosing any data
251
252 if ( --pixcount >= 1 ) {
253 *flagbyte = (char)(pixcount - 1);
254 if ( rlcount >= rlthresh ) {
255 *flagbyte |= 0x80;
256 pixcount = 1;
257 }
258
259 // copy the data into place
260 ++flagbyte;
261 flagbyte += targa_copy_data(flagbyte, copyloc, pixcount, pixsize, outsize);
262 }
263 return(flagbyte-out);
264 }
265
266 // Reads a pixel of the specified bytes_per_pixel into memory and
267 // returns the number of bytes read into memory.
268 // NOTE : for FreeSpace2, this also swizzles data into the proper screen (NOT texture) format - just like
269 // the pcxutils do.
270 //
271 // dst - A pointer to the destination. Must be at least 4 bytes long.
272 // targa_file - The file to read from.
273 // bytes_per_pixel - The bytes per pixel of the file.
274 // dest_size - bytes per pixel in destination (1 or 2. 1 == 8 bit paletted)
275 //
276 // returns - Number of byte read into memory
277 //
targa_read_pixel(int num_pixels,ubyte ** dst,ubyte ** src,int bytes_per_pixel,int dest_size)278 static void targa_read_pixel( int num_pixels, ubyte **dst, ubyte **src, int bytes_per_pixel, int dest_size )
279 {
280 int idx;
281 ushort pixel;
282 int pixel32;
283 ubyte pal_index;
284 ubyte r, g, b;
285 ubyte al = 0;
286
287 for(idx=0; idx<num_pixels; idx++){
288 // 24 or 32 bit
289 if ( (bytes_per_pixel == 3) || (bytes_per_pixel == 4) ) {
290 memset( &pixel32, 0xff, sizeof(int) );
291 memcpy( &pixel32, *src, bytes_per_pixel );
292
293 #if BYTE_ORDER == BIG_ENDIAN
294 // on big-endian it will be used as ARGB so switch it back to BGRA
295 if ( dest_size == 4 ) {
296 pixel32 = INTEL_INT(pixel32);
297 }
298 #endif
299
300 // should have it's own alpha settings so just copy it out as is
301 memcpy( *dst, &pixel32, dest_size );
302 }
303 // 8 or 16 bit
304 else {
305 // stuff the 16 bit pixel
306 memcpy(&pixel, *src, bytes_per_pixel);
307
308 pixel = INTEL_SHORT(pixel);
309
310 // if the pixel is transparent, make it so...
311 if(((pixel & 0x7c00) == 0) && ((pixel & 0x03e0) == 0x03e0) && ((pixel & 0x001f) == 0)){
312 r = b = 0;
313 g = 255;
314 al = 0;
315 bm_set_components((ubyte*)&pixel, &r, &g, &b, &al);
316 } else {
317 // get the 8 bit r, g, and b values
318 r = (ubyte)(((pixel & 0x7c00) >> 10) * 8);
319 g = (ubyte)(((pixel & 0x03e0) >> 5) * 8);
320 b = (ubyte)((pixel & 0x001f) * 8);
321 al = 1;
322
323 // now stuff these back, swizzling properly
324 pixel = 0;
325 bm_set_components((ubyte*)&pixel, &r, &g, &b, &al);
326 }
327
328 // 16 bit destination
329 if(dest_size == 2){
330 // stuff the final pixel
331 memcpy( *dst, &pixel, bytes_per_pixel );
332 }
333 // 8 bit destination
334 else {
335 pal_index = (ubyte)palette_find((int)r, (int)g, (int)b);
336 **dst = pal_index;
337 }
338 }
339
340 // next pixel
341 (*dst) += dest_size;
342 (*src) += bytes_per_pixel;
343 }
344 }
345
346 // -----------------
347 //
348 // External Functions
349 //
350 // -----------------
351
352 // Reads header information from the targa file into the bitmap pointer
353 //
354 // filename - name of the targa bitmap file
355 // w - (output) width of the bitmap
356 // h - (output) height of the bitmap
357 // bpp - (output) bits per pixel of the bitmap
358 //
359 // returns - TARGA_ERROR_NONE if successful, otherwise error code
360 //
targa_read_header(const char * real_filename,CFILE * img_cfp,int * w,int * h,int * bpp,ubyte * palette)361 int targa_read_header(const char *real_filename, CFILE *img_cfp, int *w, int *h, int *bpp, ubyte *palette )
362 {
363 targa_header header;
364 CFILE *targa_file = NULL;
365 char filename[MAX_FILENAME_LEN];
366
367 if (img_cfp == NULL) {
368 strcpy_s( filename, real_filename );
369
370 char *p = strchr( filename, '.' );
371
372 if ( p )
373 *p = 0;
374
375 strcat_s( filename, ".tga" );
376
377 targa_file = cfopen( filename , "rb" );
378
379 if ( !targa_file ) {
380 return TARGA_ERROR_READING;
381 }
382 } else {
383 targa_file = img_cfp;
384 }
385
386 header.id_length = cfread_ubyte(targa_file);
387 // header.id_length=targa_file.read_char();
388
389 header.color_map_type = cfread_ubyte(targa_file);
390 // header.color_map_type=targa_file.read_char();
391
392 header.image_type = cfread_ubyte(targa_file);
393 // header.image_type=targa_file.read_char();
394
395 header.cmap_start = cfread_short(targa_file);
396 // header.cmap_start=targa_file.read_short();
397
398 header.cmap_length = cfread_short(targa_file);
399 // header.cmap_length=targa_file.read_short();
400
401 header.cmap_depth = cfread_ubyte(targa_file);
402 // header.cmap_depth=targa_file.read_char();
403
404 header.xoffset = cfread_short(targa_file);
405 // header.xoffset=targa_file.read_short();
406
407 header.yoffset = cfread_short(targa_file);
408 // header.yoffset=targa_file.read_short();
409
410 header.width = cfread_short(targa_file);
411 // header.width=targa_file.read_short();
412
413 header.height = cfread_short(targa_file);
414 // header.height=targa_file.read_short();
415
416 header.pixel_depth = cfread_ubyte(targa_file);
417 // header.pixel_depth=targa_file.read_char();
418
419 header.image_descriptor = cfread_ubyte(targa_file);
420 // header.image_descriptor=targa_file.read_char();
421
422 if (img_cfp == NULL) {
423 cfclose(targa_file);
424 targa_file = NULL;
425 }
426
427 if ( (header.pixel_depth != 16) && (header.pixel_depth != 24) && (header.pixel_depth != 32) ) {
428 Assertion( (header.pixel_depth != 16) && (header.pixel_depth != 24) && (header.pixel_depth != 32), "Invalid colour depth (%d) in header of tga file %s\n", header.pixel_depth, real_filename );
429 return TARGA_ERROR_READING;
430 }
431
432 if (w) *w = header.width;
433 if (h) *h = header.height;
434 if (bpp) *bpp = header.pixel_depth;
435
436 return TARGA_ERROR_NONE;
437 }
438
439 // Uncompresses some RLE'd TGA data
440 //
441 // dst: pointer uncompressed destination.
442 // src: pointer to source rle'd data.
443 // bitmap_width: how many pixels to uncompress.
444 // bytes_per_pixel: bytes per pixel of the data.
445 //
446 // returns: number of input bytes processed.
447 //
targa_uncompress(ubyte * dst,ubyte * src,int bitmap_width,int bytes_per_pixel,int dest_size)448 int targa_uncompress( ubyte *dst, ubyte *src, int bitmap_width, int bytes_per_pixel, int dest_size )
449 {
450 ubyte *pixdata = dst;
451 ubyte *src_pixels = src;
452
453 int pixel_count = 0; // Initialize pixel counter
454
455 // Main decoding loop
456 while (pixel_count < bitmap_width ) {
457
458 // Get the pixel count
459 int run_count = *src_pixels++;
460
461 // Make sure writing this next run will not overflow the buffer
462 Assert(pixel_count + (run_count & 0x7f) + 1 <= bitmap_width );
463
464 // If the run is encoded...
465 if ( run_count & 0x80 ) {
466 run_count &= ~0x80; // Mask off the upper bit
467
468 // Update total pixel count
469 pixel_count += (run_count + 1);
470
471 ubyte pixel_value[4]; // temporary
472 ubyte *tmp = pixel_value;
473 targa_read_pixel( 1, &tmp, &src_pixels, bytes_per_pixel, dest_size );
474
475 // Write remainder of pixel run to buffer 'run_count' times
476 do {
477 memcpy( pixdata, pixel_value, dest_size );
478 pixdata += dest_size;
479 } while (run_count--);
480
481 } else { // ...the run is unencoded (raw)
482 // Update total pixel count
483 pixel_count += (run_count + 1);
484
485 // Read run_count pixels
486 targa_read_pixel(run_count+1, &pixdata, &src_pixels, bytes_per_pixel, dest_size );
487 }
488 }
489
490 Assert( pixel_count == bitmap_width );
491
492 return src_pixels - src;
493 }
494
495
496 // Loads a Targa bitmap
497 //
498 // filename - name of the targa file to load
499 // image_data - allocated storage for the bitmap
500 //
501 // returns - true if succesful, false otherwise
502 //
targa_read_bitmap(const char * real_filename,ubyte * image_data,ubyte * palette,int dest_size,int cf_type)503 int targa_read_bitmap(const char *real_filename, ubyte *image_data, ubyte *palette, int dest_size, int cf_type)
504 {
505 Assert(real_filename);
506 targa_header header;
507 targa_footer footer;
508 CFILE *targa_file;
509 char filename[MAX_FILENAME_LEN];
510 ubyte r, g, b;
511 int xfile_offset = 0;
512
513 // open the file
514 strcpy_s( filename, real_filename );
515 char *p = strchr( filename, '.' );
516 if ( p ) *p = 0;
517 strcat_s( filename, ".tga" );
518
519 targa_file = cfopen( filename , "rb", CFILE_NORMAL, cf_type );
520 if ( !targa_file ){
521 return TARGA_ERROR_READING;
522 }
523
524 // read the footer info first
525 cfseek( targa_file, cfilelength(targa_file) - TARGA_FOOTER_SIZE, CF_SEEK_SET );
526
527 memset( &footer, 0, sizeof(targa_footer) );
528
529 footer.ext_offset = cfread_uint(targa_file);
530 footer.dev_offset = cfread_uint(targa_file);
531
532 cfread_string(footer.sig_string, sizeof(footer.sig_string), targa_file);
533
534 if ( !strcmp(footer.sig_string, Xfile_ID) ) {
535 // it's an extended file to lets be sure to skip the extra crap which comes after the
536 // image data section, dev section comes first in the file and we only need one offset
537 if (footer.dev_offset || footer.ext_offset) {
538 xfile_offset = cfilelength(targa_file) - ((footer.dev_offset) ? footer.dev_offset : footer.ext_offset);
539 }
540 }
541
542 // done with the footer so jump back and do normal reading
543 cfseek( targa_file, 0, CF_SEEK_SET );
544
545 header.id_length = cfread_ubyte(targa_file);
546 // header.id_length=targa_file.read_char();
547
548 header.color_map_type = cfread_ubyte(targa_file);
549 // header.color_map_type=targa_file.read_char();
550
551 header.image_type = cfread_ubyte(targa_file);
552 // header.image_type=targa_file.read_char();
553
554 header.cmap_start = cfread_short(targa_file);
555 // header.cmap_start=targa_file.read_short();
556
557 header.cmap_length = cfread_short(targa_file);
558 // header.cmap_length=targa_file.read_short();
559
560 header.cmap_depth = cfread_ubyte(targa_file);
561 // header.cmap_depth=targa_file.read_char();
562
563 header.xoffset = cfread_short(targa_file);
564 // header.xoffset=targa_file.read_short();
565
566 header.yoffset = cfread_short(targa_file);
567 // header.yoffset=targa_file.read_short();
568
569 header.width = cfread_short(targa_file);
570 // header.width=targa_file.read_short();
571
572 header.height = cfread_short(targa_file);
573 // header.height=targa_file.read_short();
574
575 header.pixel_depth = cfread_ubyte(targa_file);
576 // header.pixel_depth=targa_file.read_char();
577
578 header.image_descriptor = cfread_ubyte(targa_file);
579 // header.image_descriptor=targa_file.read_char();
580
581 int bytes_per_pixel = (header.pixel_depth>>3);
582
583 // we're only allowing 2 bytes per pixel (16 bit compressed), unless Cmdline_jpgtga is used
584 Assert( (bytes_per_pixel == 2) || (bytes_per_pixel == 3) || (bytes_per_pixel == 4) );
585
586 if ( (bytes_per_pixel < 2) || (bytes_per_pixel > 4) ) {
587 cfclose(targa_file);
588 Int3();
589
590 return TARGA_ERROR_READING;
591 }
592
593 if((header.image_type!=1)&&(header.image_type!=2)&&(header.image_type!=9)&&(header.image_type!=10)) {
594 cfclose(targa_file);
595 return TARGA_ERROR_READING;
596 }
597
598 // skip the Image ID field -- should not be needed
599 if(header.id_length>0) {
600 if ( cfseek(targa_file, header.id_length, CF_SEEK_CUR) ) {
601 cfclose(targa_file);
602 return TARGA_ERROR_READING;
603 }
604 }
605
606 // read palette if one present.
607
608 if (header.color_map_type) { // non-zero indicates palette in the file
609 Int3();
610
611 // Determine the size of the color map
612 Assert(header.cmap_depth==24);
613 Assert(header.cmap_length<=256);
614 Assert(palette);
615
616 // Read the color map data
617 int i;
618 for (i = 0; i < header.cmap_length; i++) {
619 r = cfread_ubyte(targa_file);
620 g = cfread_ubyte(targa_file);
621 b = cfread_ubyte(targa_file);
622
623 if(palette != NULL){
624 palette[i*3+2] = r;
625 palette[i*3+1] = g;
626 palette[i*3+0] = b;
627 }
628 }
629 // Fill out with black.
630 if(palette != NULL){
631 for (; i < 256; i++) {
632 palette[i*3+2] = 0;
633 palette[i*3+1] = 0;
634 palette[i*3+0] = 0;
635 }
636 }
637 }
638
639 int bytes_remaining = cfilelength(targa_file) - cftell(targa_file) - xfile_offset;
640
641 Assert(bytes_remaining > 0);
642
643 ubyte *fileptr = (ubyte*)vm_malloc(bytes_remaining);
644 Assert(fileptr);
645 if(fileptr == NULL){
646 return TARGA_ERROR_READING;
647 }
648
649 ubyte *src_pixels = fileptr;
650
651 cfread(fileptr, bytes_remaining, 1, targa_file);
652
653 int rowsize = header.width * dest_size;
654
655 if ( (header.image_type == 1) || (header.image_type == 2) || (header.image_type == 3) ) {
656 // Uncompressed read
657
658 for (int i = 0; i < header.height; i++) {
659 ubyte * pixptr;
660
661 if ( ULORIGIN ) {
662 pixptr = image_data + i * rowsize;
663 } else {
664 pixptr = image_data + ((header.height - i - 1) * rowsize);
665 }
666
667 targa_read_pixel(header.width, &pixptr, &src_pixels, bytes_per_pixel, dest_size );
668 }
669
670 } else if (header.image_type == 9 || header.image_type == 10 || header.image_type == 11) {
671 // the following handles RLE'ed targa data.
672
673 // targas encoded by the scanline -- loop on the height
674 for (int i = 0; i < header.height; i++) {
675 ubyte *pixdata;
676
677 if (ULORIGIN) {
678 pixdata = image_data + i * rowsize;
679 } else {
680 pixdata = image_data + ((header.height - i - 1) * rowsize);
681 }
682
683 src_pixels += targa_uncompress( pixdata, src_pixels, header.width, bytes_per_pixel, dest_size );
684 }
685
686 }
687
688 vm_free(fileptr);
689 cfclose(targa_file);
690 targa_file = NULL;
691
692 return TARGA_ERROR_NONE;
693 }
694
695 // Write out a Targa format bitmap. Always writes out a top-up bitmap.
696 // JAS: DOESN'T WORK WITH 8-BPP PALETTES
697 //
698 // filename: name of the Targa file, .tga extension added if not passed in
699 // data: raw image data
700 // w: width of the bitmap in pixels
701 // h: height of the bitmap in pixels
702 // bpp: bits per pixel of the bitmap
703 //
704 // returns: 0 if successful, otherwise -1
705 //
targa_write_bitmap(char * real_filename,ubyte * data,ubyte * palette,int w,int h,int bpp)706 int targa_write_bitmap(char *real_filename, ubyte *data, ubyte *palette, int w, int h, int bpp)
707 {
708 Assert(bpp == 24);
709 char filename[MAX_FILENAME_LEN];
710 CFILE *f;
711 int bytes_per_pixel = (bpp >> 3);
712
713 // open the file
714 strcpy_s( filename, real_filename );
715 char *p = strchr( filename, '.' );
716 if ( p ) *p = 0;
717 strcat_s( filename, ".tga" );
718
719 f = cfopen( filename , "wb" );
720 if ( !f ){
721 return TARGA_ERROR_READING;
722 }
723
724 // Write the TGA header
725 cfwrite_ubyte(0, f);
726 // f.write_ubyte(0); // IDLength
727
728 cfwrite_ubyte(0, f);
729 //f.write_ubyte(0); // ColorMapType
730
731 cfwrite_ubyte(10, f);
732 // f.write_ubyte(10); // image_type: 2 = 24bpp, uncompressed, 10=24bpp rle compressed
733
734 cfwrite_ushort(0, f);
735 // f.write_ushort(0); // CMapStart
736
737 cfwrite_ushort(0, f);
738 // f.write_ushort(0); // CMapLength
739
740 cfwrite_ubyte(0, f);
741 // f.write_ubyte(0); // CMapDepth
742
743 cfwrite_ushort(0, f);
744 // f.write_ushort(0); // XOffset
745
746 cfwrite_ushort(0, f);
747 // f.write_ushort(0); // YOffset
748
749 cfwrite_ushort((ushort)w, f);
750 // f.write_ushort((ushort)w); // Width
751
752 cfwrite_ushort((ushort)h, f);
753 // f.write_ushort((ushort)h); // Height
754
755 cfwrite_ubyte(24, f);
756 // f.write_ubyte(24); // pixel_depth
757
758 cfwrite_ubyte(0x20, f);
759 // f.write_ubyte(0x20); // ImageDesc ( 0x20 = Origin at upper left )
760
761 ubyte *compressed_data;
762 compressed_data = (ubyte*)vm_malloc(w * h * bytes_per_pixel);
763 Assert(compressed_data);
764 if(compressed_data == NULL){
765 cfclose(f);
766 return -1;
767 }
768
769 int compressed_data_len;
770 compressed_data_len = targa_compress((char*)compressed_data, (char*)data, 3, bytes_per_pixel, w * h * bytes_per_pixel);
771 if (compressed_data_len < 0) {
772 vm_free(compressed_data);
773 cfclose(f);
774 return -1;
775 }
776
777 cfwrite(compressed_data, compressed_data_len, 1, f);
778 cfclose(f);
779 f = NULL;
780
781 return 0;
782 }
783