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