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