]> de.git.xonotic.org Git - voretournament/voretournament.git/blob - misc/mediasource/extra/netradiant-src/tools/quake2/common/lbmlib.c
Include netRadiant source in this GIT
[voretournament/voretournament.git] / misc / mediasource / extra / netradiant-src / tools / quake2 / common / lbmlib.c
1 /*
2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21 // lbmlib.c
22
23 #include "cmdlib.h"
24 #include "inout.h"
25 #include "lbmlib.h"
26
27
28
29 /*
30 ============================================================================
31
32                                                 LBM STUFF
33
34 ============================================================================
35 */
36
37
38 typedef unsigned char   UBYTE;
39 //conflicts with windows typedef short                  WORD;
40 typedef unsigned short  UWORD;
41 typedef long                    LONG;
42
43 typedef enum
44 {
45         ms_none,
46         ms_mask,
47         ms_transcolor,
48         ms_lasso
49 } mask_t;
50
51 typedef enum
52 {
53         cm_none,
54         cm_rle1
55 } compress_t;
56
57 typedef struct
58 {
59         UWORD           w,h;
60         short           x,y;
61         UBYTE           nPlanes;
62         UBYTE           masking;
63         UBYTE           compression;
64         UBYTE           pad1;
65         UWORD           transparentColor;
66         UBYTE           xAspect,yAspect;
67         short           pageWidth,pageHeight;
68 } bmhd_t;
69
70 extern  bmhd_t  bmhd;                                           // will be in native byte order
71
72
73
74 #define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24))
75 #define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24))
76 #define PBMID  ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24))
77 #define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24))
78 #define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24))
79 #define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24))
80
81
82 bmhd_t  bmhd;
83
84 int    Align (int l)
85 {
86         if (l&1)
87                 return l+1;
88         return l;
89 }
90
91
92
93 /*
94 ================
95 LBMRLEdecompress
96
97 Source must be evenly aligned!
98 ================
99 */
100 byte  *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth)
101 {
102         int     count;
103         byte    b,rept;
104
105         count = 0;
106
107         do
108         {
109                 rept = *source++;
110
111                 if (rept > 0x80)
112                 {
113                         rept = (rept^0xff)+2;
114                         b = *source++;
115                         memset(unpacked,b,rept);
116                         unpacked += rept;
117                 }
118                 else if (rept < 0x80)
119                 {
120                         rept++;
121                         memcpy(unpacked,source,rept);
122                         unpacked += rept;
123                         source += rept;
124                 }
125                 else
126                         rept = 0;               // rept of 0x80 is NOP
127
128                 count += rept;
129
130         } while (count<bpwidth);
131
132         if (count>bpwidth)
133                 Error ("Decompression exceeded width!\n");
134
135
136         return source;
137 }
138
139
140 /*
141 =================
142 LoadLBM
143 =================
144 */
145 void LoadLBM (char *filename, byte **picture, byte **palette)
146 {
147         byte    *LBMbuffer, *picbuffer, *cmapbuffer;
148         int             y;
149         byte    *LBM_P, *LBMEND_P;
150         byte    *pic_p;
151         byte    *body_p;
152
153         int    formtype,formlength;
154         int    chunktype,chunklength;
155
156 // qiet compiler warnings
157         picbuffer = NULL;
158         cmapbuffer = NULL;
159
160 //
161 // load the LBM
162 //
163         LoadFile (filename, (void **)&LBMbuffer);
164
165 //
166 // parse the LBM header
167 //
168         LBM_P = LBMbuffer;
169         if ( *(int *)LBMbuffer != LittleLong(FORMID) )
170            Error ("No FORM ID at start of file!\n");
171
172         LBM_P += 4;
173         formlength = BigLong( *(int *)LBM_P );
174         LBM_P += 4;
175         LBMEND_P = LBM_P + Align(formlength);
176
177         formtype = LittleLong(*(int *)LBM_P);
178
179         if (formtype != ILBMID && formtype != PBMID)
180                 Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff
181                 ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff);
182
183         LBM_P += 4;
184
185 //
186 // parse chunks
187 //
188
189         while (LBM_P < LBMEND_P)
190         {
191                 chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24);
192                 LBM_P += 4;
193                 chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24);
194                 LBM_P += 4;
195
196                 switch ( chunktype )
197                 {
198                 case BMHDID:
199                         memcpy (&bmhd,LBM_P,sizeof(bmhd));
200                         bmhd.w = BigShort(bmhd.w);
201                         bmhd.h = BigShort(bmhd.h);
202                         bmhd.x = BigShort(bmhd.x);
203                         bmhd.y = BigShort(bmhd.y);
204                         bmhd.pageWidth = BigShort(bmhd.pageWidth);
205                         bmhd.pageHeight = BigShort(bmhd.pageHeight);
206                         break;
207
208                 case CMAPID:
209                         cmapbuffer = malloc (768);
210                         memset (cmapbuffer, 0, 768);
211                         memcpy (cmapbuffer, LBM_P, chunklength);
212                         break;
213
214                 case BODYID:
215                         body_p = LBM_P;
216
217                         pic_p = picbuffer = malloc (bmhd.w*bmhd.h);
218                         if (formtype == PBMID)
219                         {
220                         //
221                         // unpack PBM
222                         //
223                                 for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
224                                 {
225                                         if (bmhd.compression == cm_rle1)
226                                                 body_p = LBMRLEDecompress ((byte *)body_p
227                                                 , pic_p , bmhd.w);
228                                         else if (bmhd.compression == cm_none)
229                                         {
230                                                 memcpy (pic_p,body_p,bmhd.w);
231                                                 body_p += Align(bmhd.w);
232                                         }
233                                 }
234
235                         }
236                         else
237                         {
238                         //
239                         // unpack ILBM
240                         //
241                                 Error ("%s is an interlaced LBM, not packed", filename);
242                         }
243                         break;
244                 }
245
246                 LBM_P += Align(chunklength);
247         }
248
249         free (LBMbuffer);
250
251         *picture = picbuffer;
252
253         if (palette)
254                 *palette = cmapbuffer;
255 }
256
257
258 /*
259 ============================================================================
260
261                                                         WRITE LBM
262
263 ============================================================================
264 */
265
266 /*
267 ==============
268 WriteLBMfile
269 ==============
270 */
271 void WriteLBMfile (char *filename, byte *data,
272                                    int width, int height, byte *palette)
273 {
274         byte    *lbm, *lbmptr;
275         int    *formlength, *bmhdlength, *cmaplength, *bodylength;
276         int    length;
277         bmhd_t  basebmhd;
278
279         lbm = lbmptr = malloc (width*height+1000);
280
281 //
282 // start FORM
283 //
284         *lbmptr++ = 'F';
285         *lbmptr++ = 'O';
286         *lbmptr++ = 'R';
287         *lbmptr++ = 'M';
288
289         formlength = (int*)lbmptr;
290         lbmptr+=4;                      // leave space for length
291
292         *lbmptr++ = 'P';
293         *lbmptr++ = 'B';
294         *lbmptr++ = 'M';
295         *lbmptr++ = ' ';
296
297 //
298 // write BMHD
299 //
300         *lbmptr++ = 'B';
301         *lbmptr++ = 'M';
302         *lbmptr++ = 'H';
303         *lbmptr++ = 'D';
304
305         bmhdlength = (int *)lbmptr;
306         lbmptr+=4;                      // leave space for length
307
308         memset (&basebmhd,0,sizeof(basebmhd));
309         basebmhd.w = BigShort((short)width);
310         basebmhd.h = BigShort((short)height);
311         basebmhd.nPlanes = BigShort(8);
312         basebmhd.xAspect = BigShort(5);
313         basebmhd.yAspect = BigShort(6);
314         basebmhd.pageWidth = BigShort((short)width);
315         basebmhd.pageHeight = BigShort((short)height);
316
317         memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
318         lbmptr += sizeof(basebmhd);
319
320         length = lbmptr-(byte *)bmhdlength-4;
321         *bmhdlength = BigLong(length);
322         if (length&1)
323                 *lbmptr++ = 0;          // pad chunk to even offset
324
325 //
326 // write CMAP
327 //
328         *lbmptr++ = 'C';
329         *lbmptr++ = 'M';
330         *lbmptr++ = 'A';
331         *lbmptr++ = 'P';
332
333         cmaplength = (int *)lbmptr;
334         lbmptr+=4;                      // leave space for length
335
336         memcpy (lbmptr,palette,768);
337         lbmptr += 768;
338
339         length = lbmptr-(byte *)cmaplength-4;
340         *cmaplength = BigLong(length);
341         if (length&1)
342                 *lbmptr++ = 0;          // pad chunk to even offset
343
344 //
345 // write BODY
346 //
347         *lbmptr++ = 'B';
348         *lbmptr++ = 'O';
349         *lbmptr++ = 'D';
350         *lbmptr++ = 'Y';
351
352         bodylength = (int *)lbmptr;
353         lbmptr+=4;                      // leave space for length
354
355         memcpy (lbmptr,data,width*height);
356         lbmptr += width*height;
357
358         length = lbmptr-(byte *)bodylength-4;
359         *bodylength = BigLong(length);
360         if (length&1)
361                 *lbmptr++ = 0;          // pad chunk to even offset
362
363 //
364 // done
365 //
366         length = lbmptr-(byte *)formlength-4;
367         *formlength = BigLong(length);
368         if (length&1)
369                 *lbmptr++ = 0;          // pad chunk to even offset
370
371 //
372 // write output file
373 //
374         SaveFile (filename, lbm, lbmptr-lbm);
375         free (lbm);
376 }
377
378
379 /*
380 ============================================================================
381
382 LOAD PCX
383
384 ============================================================================
385 */
386
387 typedef struct
388 {
389     char        manufacturer;
390     char        version;
391     char        encoding;
392     char        bits_per_pixel;
393     unsigned short      xmin,ymin,xmax,ymax;
394     unsigned short      hres,vres;
395     unsigned char       palette[48];
396     char        reserved;
397     char        color_planes;
398     unsigned short      bytes_per_line;
399     unsigned short      palette_type;
400     char        filler[58];
401     unsigned char       data;                   // unbounded
402 } pcx_t;
403
404
405 /*
406 ==============
407 LoadPCX
408 ==============
409 */
410 void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
411 {
412         byte    *raw;
413         pcx_t   *pcx;
414         int             x, y;
415         int             len;
416         int             dataByte, runLength;
417         byte    *out, *pix;
418
419         //
420         // load the file
421         //
422         len = LoadFile (filename, (void **)&raw);
423
424         //
425         // parse the PCX file
426         //
427         pcx = (pcx_t *)raw;
428         raw = &pcx->data;
429
430         pcx->xmin = LittleShort(pcx->xmin);
431         pcx->ymin = LittleShort(pcx->ymin);
432         pcx->xmax = LittleShort(pcx->xmax);
433         pcx->ymax = LittleShort(pcx->ymax);
434         pcx->hres = LittleShort(pcx->hres);
435         pcx->vres = LittleShort(pcx->vres);
436         pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
437         pcx->palette_type = LittleShort(pcx->palette_type);
438
439         if (pcx->manufacturer != 0x0a
440                 || pcx->version != 5
441                 || pcx->encoding != 1
442                 || pcx->bits_per_pixel != 8
443                 || pcx->xmax >= 640
444                 || pcx->ymax >= 480)
445                 Error ("Bad pcx file %s", filename);
446         
447         if (palette)
448         {
449                 *palette = malloc(768);
450                 memcpy (*palette, (byte *)pcx + len - 768, 768);
451         }
452
453         if (width)
454                 *width = pcx->xmax+1;
455         if (height)
456                 *height = pcx->ymax+1;
457
458         if (!pic)
459                 return;
460
461         out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
462         if (!out)
463                 Error ("Skin_Cache: couldn't allocate");
464
465         *pic = out;
466
467         pix = out;
468
469         for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
470         {
471                 for (x=0 ; x<=pcx->xmax ; )
472                 {
473                         dataByte = *raw++;
474
475                         if((dataByte & 0xC0) == 0xC0)
476                         {
477                                 runLength = dataByte & 0x3F;
478                                 dataByte = *raw++;
479                         }
480                         else
481                                 runLength = 1;
482
483                         while(runLength-- > 0)
484                                 pix[x++] = dataByte;
485                 }
486
487         }
488
489         if ( raw - (byte *)pcx > len)
490                 Error ("PCX file %s was malformed", filename);
491
492         free (pcx);
493 }
494
495 /* 
496 ============== 
497 WritePCXfile 
498 ============== 
499 */ 
500 void WritePCXfile (char *filename, byte *data, 
501                                    int width, int height, byte *palette) 
502 {
503         int             i, j, length;
504         pcx_t   *pcx;
505         byte            *pack;
506           
507         pcx = malloc (width*height*2+1000);
508         memset (pcx, 0, sizeof(*pcx));
509
510         pcx->manufacturer = 0x0a;       // PCX id
511         pcx->version = 5;                       // 256 color
512         pcx->encoding = 1;              // uncompressed
513         pcx->bits_per_pixel = 8;                // 256 color
514         pcx->xmin = 0;
515         pcx->ymin = 0;
516         pcx->xmax = LittleShort((short)(width-1));
517         pcx->ymax = LittleShort((short)(height-1));
518         pcx->hres = LittleShort((short)width);
519         pcx->vres = LittleShort((short)height);
520         pcx->color_planes = 1;          // chunky image
521         pcx->bytes_per_line = LittleShort((short)width);
522         pcx->palette_type = LittleShort(2);             // not a grey scale
523
524         // pack the image
525         pack = &pcx->data;
526         
527         for (i=0 ; i<height ; i++)
528         {
529                 for (j=0 ; j<width ; j++)
530                 {
531                         if ( (*data & 0xc0) != 0xc0)
532                                 *pack++ = *data++;
533                         else
534                         {
535                                 *pack++ = 0xc1;
536                                 *pack++ = *data++;
537                         }
538                 }
539         }
540                         
541         // write the palette
542         *pack++ = 0x0c; // palette ID byte
543         for (i=0 ; i<768 ; i++)
544                 *pack++ = *palette++;
545                 
546 // write output file 
547         length = pack - (byte *)pcx;
548         SaveFile (filename, pcx, length);
549
550         free (pcx);
551
552  
553
554 /*
555 ============================================================================
556
557 LOAD IMAGE
558
559 ============================================================================
560 */
561
562 /*
563 ==============
564 Load256Image
565
566 Will load either an lbm or pcx, depending on extension.
567 Any of the return pointers can be NULL if you don't want them.
568 ==============
569 */
570 void Load256Image (char *name, byte **pixels, byte **palette,
571                                    int *width, int *height)
572 {
573         char    ext[128];
574
575         ExtractFileExtension (name, ext);
576         if (!Q_strncasecmp (ext, "lbm", strlen(ext) ))
577         {
578                 LoadLBM (name, pixels, palette);
579                 if (width)
580                         *width = bmhd.w;
581                 if (height)
582                         *height = bmhd.h;
583         }
584         else if (!Q_strncasecmp (ext, "pcx",strlen(ext)))
585         {
586                 LoadPCX (name, pixels, palette, width, height);
587         }
588         else
589                 Error ("%s doesn't have a known image extension", name);
590 }
591
592
593 /*
594 ==============
595 Save256Image
596
597 Will save either an lbm or pcx, depending on extension.
598 ==============
599 */
600 void Save256Image (char *name, byte *pixels, byte *palette,
601                                    int width, int height)
602 {
603         char    ext[128];
604
605         ExtractFileExtension (name, ext);
606         if (!Q_strncasecmp (ext, "lbm",strlen(ext)))
607         {
608                 WriteLBMfile (name, pixels, width, height, palette);
609         }
610         else if (!Q_strncasecmp (ext, "pcx",strlen(ext)))
611         {
612                 WritePCXfile (name, pixels, width, height, palette);
613         }
614         else
615                 Error ("%s doesn't have a known image extension", name);
616 }
617
618
619
620
621 /*
622 ============================================================================
623
624 TARGA IMAGE
625
626 ============================================================================
627 */
628
629 typedef struct _TargaHeader {
630         unsigned char   id_length, colormap_type, image_type;
631         unsigned short  colormap_index, colormap_length;
632         unsigned char   colormap_size;
633         unsigned short  x_origin, y_origin, width, height;
634         unsigned char   pixel_size, attributes;
635 } TargaHeader;
636
637 int fgetLittleShort (FILE *f)
638 {
639         byte    b1, b2;
640
641         b1 = fgetc(f);
642         b2 = fgetc(f);
643
644         return (short)(b1 + b2*256);
645 }
646
647 int fgetLittleLong (FILE *f)
648 {
649         byte    b1, b2, b3, b4;
650
651         b1 = fgetc(f);
652         b2 = fgetc(f);
653         b3 = fgetc(f);
654         b4 = fgetc(f);
655
656         return b1 + (b2<<8) + (b3<<16) + (b4<<24);
657 }
658
659
660 /*
661 =============
662 LoadTGA
663 =============
664 */
665 void LoadTGA (char *name, byte **pixels, int *width, int *height)
666 {
667         int                             columns, rows, numPixels;
668         byte                    *pixbuf;
669         int                             row, column;
670         FILE                    *fin;
671         byte                    *targa_rgba;
672         TargaHeader             targa_header;
673
674         fin = fopen (name, "rb");
675         if (!fin)
676                 Error ("Couldn't read %s", name);
677
678         targa_header.id_length = fgetc(fin);
679         targa_header.colormap_type = fgetc(fin);
680         targa_header.image_type = fgetc(fin);
681         
682         targa_header.colormap_index = fgetLittleShort(fin);
683         targa_header.colormap_length = fgetLittleShort(fin);
684         targa_header.colormap_size = fgetc(fin);
685         targa_header.x_origin = fgetLittleShort(fin);
686         targa_header.y_origin = fgetLittleShort(fin);
687         targa_header.width = fgetLittleShort(fin);
688         targa_header.height = fgetLittleShort(fin);
689         targa_header.pixel_size = fgetc(fin);
690         targa_header.attributes = fgetc(fin);
691
692         if (targa_header.image_type!=2 
693                 && targa_header.image_type!=10) 
694                 Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
695
696         if (targa_header.colormap_type !=0 
697                 || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
698                 Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
699
700         columns = targa_header.width;
701         rows = targa_header.height;
702         numPixels = columns * rows;
703
704         if (width)
705                 *width = columns;
706         if (height)
707                 *height = rows;
708         targa_rgba = malloc(numPixels*4);
709         *pixels = targa_rgba;
710
711         if (targa_header.id_length != 0)
712                 fseek(fin, targa_header.id_length, SEEK_CUR);  // skip TARGA image comment
713         
714         if (targa_header.image_type==2) {  // Uncompressed, RGB images
715                 for(row=rows-1; row>=0; row--) {
716                         pixbuf = targa_rgba + row*columns*4;
717                         for(column=0; column<columns; column++) {
718                                 unsigned char red,green,blue,alphabyte;
719                                 switch (targa_header.pixel_size) {
720                                         case 24:
721                                                         
722                                                         blue = getc(fin);
723                                                         green = getc(fin);
724                                                         red = getc(fin);
725                                                         *pixbuf++ = red;
726                                                         *pixbuf++ = green;
727                                                         *pixbuf++ = blue;
728                                                         *pixbuf++ = 255;
729                                                         break;
730                                         case 32:
731                                                         blue = getc(fin);
732                                                         green = getc(fin);
733                                                         red = getc(fin);
734                                                         alphabyte = getc(fin);
735                                                         *pixbuf++ = red;
736                                                         *pixbuf++ = green;
737                                                         *pixbuf++ = blue;
738                                                         *pixbuf++ = alphabyte;
739                                                         break;
740                                 }
741                         }
742                 }
743         }
744         else if (targa_header.image_type==10) {   // Runlength encoded RGB images
745                 unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
746                 for(row=rows-1; row>=0; row--) {
747                         pixbuf = targa_rgba + row*columns*4;
748                         for(column=0; column<columns; ) {
749                                 packetHeader=getc(fin);
750                                 packetSize = 1 + (packetHeader & 0x7f);
751                                 if (packetHeader & 0x80) {        // run-length packet
752                                         switch (targa_header.pixel_size) {
753                                                 case 24:
754                                                                 blue = getc(fin);
755                                                                 green = getc(fin);
756                                                                 red = getc(fin);
757                                                                 alphabyte = 255;
758                                                                 break;
759                                                 case 32:
760                                                                 blue = getc(fin);
761                                                                 green = getc(fin);
762                                                                 red = getc(fin);
763                                                                 alphabyte = getc(fin);
764                                                                 break;
765                                         }
766         
767                                         for(j=0;j<packetSize;j++) {
768                                                 *pixbuf++=red;
769                                                 *pixbuf++=green;
770                                                 *pixbuf++=blue;
771                                                 *pixbuf++=alphabyte;
772                                                 column++;
773                                                 if (column==columns) { // run spans across rows
774                                                         column=0;
775                                                         if (row>0)
776                                                                 row--;
777                                                         else
778                                                                 goto breakOut;
779                                                         pixbuf = targa_rgba + row*columns*4;
780                                                 }
781                                         }
782                                 }
783                                 else {                            // non run-length packet
784                                         for(j=0;j<packetSize;j++) {
785                                                 switch (targa_header.pixel_size) {
786                                                         case 24:
787                                                                         blue = getc(fin);
788                                                                         green = getc(fin);
789                                                                         red = getc(fin);
790                                                                         *pixbuf++ = red;
791                                                                         *pixbuf++ = green;
792                                                                         *pixbuf++ = blue;
793                                                                         *pixbuf++ = 255;
794                                                                         break;
795                                                         case 32:
796                                                                         blue = getc(fin);
797                                                                         green = getc(fin);
798                                                                         red = getc(fin);
799                                                                         alphabyte = getc(fin);
800                                                                         *pixbuf++ = red;
801                                                                         *pixbuf++ = green;
802                                                                         *pixbuf++ = blue;
803                                                                         *pixbuf++ = alphabyte;
804                                                                         break;
805                                                 }
806                                                 column++;
807                                                 if (column==columns) { // pixel packet run spans across rows
808                                                         column=0;
809                                                         if (row>0)
810                                                                 row--;
811                                                         else
812                                                                 goto breakOut;
813                                                         pixbuf = targa_rgba + row*columns*4;
814                                                 }                                               
815                                         }
816                                 }
817                         }
818                         breakOut:;
819                 }
820         }
821
822         // vertically flipped
823         if ( (targa_header.attributes & (1<<5)) ) {
824                 int flip;
825                 for (row = 0; row < .5f * rows; row++)
826                 {
827                         for (column = 0; column < columns; column++)
828                         {
829                                 flip = *( (int*)targa_rgba + row * columns + column);
830                                 *( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column );
831                                 *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip;
832                         }
833                 }
834         }
835         
836         fclose(fin);
837 }