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