]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/qdata_heretic2/common/lbmlib.c
Merge branch 'master' into divVerent/farplanedist-sky-fix
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / 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
22 // lbmlib.c
23
24 #include "cmdlib.h"
25 #include "inout.h"
26 #include "lbmlib.h"
27
28 // Ups the palette values so no pixels except 0 appear transparent
29 // Need a value of 8 to cater for 16bit renderers
30
31 typedef struct
32 {
33         byte r;
34         byte g;
35         byte b;
36 } paletteRGB_t;
37
38
39 void CorrectPalette( byte *pal ){
40         paletteRGB_t    *p;
41
42         p = (paletteRGB_t *)pal;
43         // Color 0 always transparent
44         p->r = 0;
45         p->g = 0;
46         p->b = 0;
47 }
48
49 /*
50    ============================================================================
51
52                         LBM STUFF
53
54    ============================================================================
55  */
56
57
58 typedef unsigned char UBYTE;
59 //conflicts with windows typedef short                  WORD;
60 typedef unsigned short UWORD;
61 typedef long LONG;
62
63 typedef enum
64 {
65         ms_none,
66         ms_mask,
67         ms_transcolor,
68         ms_lasso
69 } mask_t;
70
71 typedef enum
72 {
73         cm_none,
74         cm_rle1
75 } compress_t;
76
77 typedef struct
78 {
79         UWORD w,h;
80         short x,y;
81         UBYTE nPlanes;
82         UBYTE masking;
83         UBYTE compression;
84         UBYTE pad1;
85         UWORD transparentColor;
86         UBYTE xAspect,yAspect;
87         short pageWidth,pageHeight;
88 } bmhd_t;
89
90 extern bmhd_t bmhd;                         // will be in native byte order
91
92
93
94 #define FORMID ( 'F' + ( 'O' << 8 ) + ( (int)'R' << 16 ) + ( (int)'M' << 24 ) )
95 #define ILBMID ( 'I' + ( 'L' << 8 ) + ( (int)'B' << 16 ) + ( (int)'M' << 24 ) )
96 #define PBMID  ( 'P' + ( 'B' << 8 ) + ( (int)'M' << 16 ) + ( (int)' ' << 24 ) )
97 #define BMHDID ( 'B' + ( 'M' << 8 ) + ( (int)'H' << 16 ) + ( (int)'D' << 24 ) )
98 #define BODYID ( 'B' + ( 'O' << 8 ) + ( (int)'D' << 16 ) + ( (int)'Y' << 24 ) )
99 #define CMAPID ( 'C' + ( 'M' << 8 ) + ( (int)'A' << 16 ) + ( (int)'P' << 24 ) )
100
101
102 bmhd_t bmhd;
103
104 int    Align( int l ){
105         if ( l & 1 ) {
106                 return l + 1;
107         }
108         return l;
109 }
110
111
112
113 /*
114    ================
115    LBMRLEdecompress
116
117    Source must be evenly aligned!
118    ================
119  */
120 byte  *LBMRLEDecompress( byte *source,byte *unpacked, int bpwidth ){
121         int count;
122         byte b,rept;
123
124         count = 0;
125
126         do
127         {
128                 rept = *source++;
129
130                 if ( rept > 0x80 ) {
131                         rept = ( rept ^ 0xff ) + 2;
132                         b = *source++;
133                         memset( unpacked,b,rept );
134                         unpacked += rept;
135                 }
136                 else if ( rept < 0x80 ) {
137                         rept++;
138                         memcpy( unpacked,source,rept );
139                         unpacked += rept;
140                         source += rept;
141                 }
142                 else{
143                         rept = 0;               // rept of 0x80 is NOP
144
145                 }
146                 count += rept;
147
148         } while ( count < bpwidth );
149
150         if ( count > bpwidth ) {
151                 Error( "Decompression exceeded width!\n" );
152         }
153
154
155         return source;
156 }
157
158
159 /*
160    =================
161    LoadLBM
162    =================
163  */
164 void LoadLBM( char *filename, byte **picture, byte **palette ){
165         byte    *LBMbuffer, *picbuffer, *cmapbuffer;
166         int y;
167         byte    *LBM_P, *LBMEND_P;
168         byte    *pic_p;
169         byte    *body_p;
170
171         int formtype,formlength;
172         int chunktype,chunklength;
173
174 // qiet compiler warnings
175         picbuffer = NULL;
176         cmapbuffer = NULL;
177
178 //
179 // load the LBM
180 //
181         LoadFile( filename, (void **)&LBMbuffer );
182
183 //
184 // parse the LBM header
185 //
186         LBM_P = LBMbuffer;
187         if ( *(int *)LBMbuffer != LittleLong( FORMID ) ) {
188                 Error( "No FORM ID at start of file!\n" );
189         }
190
191         LBM_P += 4;
192         formlength = BigLong( *(int *)LBM_P );
193         LBM_P += 4;
194         LBMEND_P = LBM_P + Align( formlength );
195
196         formtype = LittleLong( *(int *)LBM_P );
197
198         if ( formtype != ILBMID && formtype != PBMID ) {
199                 Error( "Unrecognized form type: %c%c%c%c\n", formtype & 0xff
200                            ,( formtype >> 8 ) & 0xff,( formtype >> 16 ) & 0xff,( formtype >> 24 ) & 0xff );
201         }
202
203         LBM_P += 4;
204
205 //
206 // parse chunks
207 //
208
209         while ( LBM_P < LBMEND_P )
210         {
211                 chunktype = LBM_P[0] + ( LBM_P[1] << 8 ) + ( LBM_P[2] << 16 ) + ( LBM_P[3] << 24 );
212                 LBM_P += 4;
213                 chunklength = LBM_P[3] + ( LBM_P[2] << 8 ) + ( LBM_P[1] << 16 ) + ( LBM_P[0] << 24 );
214                 LBM_P += 4;
215
216                 switch ( chunktype )
217                 {
218                 case BMHDID:
219                         memcpy( &bmhd,LBM_P,sizeof( bmhd ) );
220                         bmhd.w = BigShort( bmhd.w );
221                         bmhd.h = BigShort( bmhd.h );
222                         bmhd.x = BigShort( bmhd.x );
223                         bmhd.y = BigShort( bmhd.y );
224                         bmhd.pageWidth = BigShort( bmhd.pageWidth );
225                         bmhd.pageHeight = BigShort( bmhd.pageHeight );
226                         break;
227
228                 case CMAPID:
229                         cmapbuffer = malloc( 768 );
230                         memset( cmapbuffer, 0, 768 );
231                         memcpy( cmapbuffer, LBM_P, chunklength );
232                         CorrectPalette( cmapbuffer );
233                         break;
234
235                 case BODYID:
236                         body_p = LBM_P;
237
238                         pic_p = picbuffer = malloc( bmhd.w * bmhd.h );
239                         if ( formtype == PBMID ) {
240                                 //
241                                 // unpack PBM
242                                 //
243                                 for ( y = 0 ; y < bmhd.h ; y++, pic_p += bmhd.w )
244                                 {
245                                         if ( bmhd.compression == cm_rle1 ) {
246                                                 body_p = LBMRLEDecompress( (byte *)body_p
247                                                                                                    , pic_p, bmhd.w );
248                                         }
249                                         else if ( bmhd.compression == cm_none ) {
250                                                 memcpy( pic_p,body_p,bmhd.w );
251                                                 body_p += Align( bmhd.w );
252                                         }
253                                 }
254
255                         }
256                         else
257                         {
258                                 //
259                                 // unpack ILBM
260                                 //
261                                 Error( "%s is an interlaced LBM, not packed", filename );
262                         }
263                         break;
264                 }
265
266                 LBM_P += Align( chunklength );
267         }
268
269         free( LBMbuffer );
270
271         *picture = picbuffer;
272
273         if ( palette ) {
274                 *palette = cmapbuffer;
275         }
276 }
277
278
279 /*
280    ============================================================================
281
282                             WRITE LBM
283
284    ============================================================================
285  */
286
287 /*
288    ==============
289    WriteLBMfile
290    ==============
291  */
292 void WriteLBMfile( char *filename, byte *data,
293                                    int width, int height, byte *palette ){
294         byte    *lbm, *lbmptr;
295         int    *formlength, *bmhdlength, *cmaplength, *bodylength;
296         int length;
297         bmhd_t basebmhd;
298
299         lbm = lbmptr = malloc( width * height + 1000 );
300
301 //
302 // start FORM
303 //
304         *lbmptr++ = 'F';
305         *lbmptr++ = 'O';
306         *lbmptr++ = 'R';
307         *lbmptr++ = 'M';
308
309         formlength = (int*)lbmptr;
310         lbmptr += 4;                      // leave space for length
311
312         *lbmptr++ = 'P';
313         *lbmptr++ = 'B';
314         *lbmptr++ = 'M';
315         *lbmptr++ = ' ';
316
317 //
318 // write BMHD
319 //
320         *lbmptr++ = 'B';
321         *lbmptr++ = 'M';
322         *lbmptr++ = 'H';
323         *lbmptr++ = 'D';
324
325         bmhdlength = (int *)lbmptr;
326         lbmptr += 4;                      // leave space for length
327
328         memset( &basebmhd,0,sizeof( basebmhd ) );
329         basebmhd.w = BigShort( (short)width );
330         basebmhd.h = BigShort( (short)height );
331         basebmhd.nPlanes = BigShort( 8 );
332         basebmhd.xAspect = BigShort( 5 );
333         basebmhd.yAspect = BigShort( 6 );
334         basebmhd.pageWidth = BigShort( (short)width );
335         basebmhd.pageHeight = BigShort( (short)height );
336
337         memcpy( lbmptr,&basebmhd,sizeof( basebmhd ) );
338         lbmptr += sizeof( basebmhd );
339
340         length = lbmptr - (byte *)bmhdlength - 4;
341         *bmhdlength = BigLong( length );
342         if ( length & 1 ) {
343                 *lbmptr++ = 0;          // pad chunk to even offset
344
345         }
346 //
347 // write CMAP
348 //
349         *lbmptr++ = 'C';
350         *lbmptr++ = 'M';
351         *lbmptr++ = 'A';
352         *lbmptr++ = 'P';
353
354         cmaplength = (int *)lbmptr;
355         lbmptr += 4;                      // leave space for length
356
357         memcpy( lbmptr,palette,768 );
358         lbmptr += 768;
359
360         length = lbmptr - (byte *)cmaplength - 4;
361         *cmaplength = BigLong( length );
362         if ( length & 1 ) {
363                 *lbmptr++ = 0;          // pad chunk to even offset
364
365         }
366 //
367 // write BODY
368 //
369         *lbmptr++ = 'B';
370         *lbmptr++ = 'O';
371         *lbmptr++ = 'D';
372         *lbmptr++ = 'Y';
373
374         bodylength = (int *)lbmptr;
375         lbmptr += 4;                      // leave space for length
376
377         memcpy( lbmptr,data,width * height );
378         lbmptr += width * height;
379
380         length = lbmptr - (byte *)bodylength - 4;
381         *bodylength = BigLong( length );
382         if ( length & 1 ) {
383                 *lbmptr++ = 0;          // pad chunk to even offset
384
385         }
386 //
387 // done
388 //
389         length = lbmptr - (byte *)formlength - 4;
390         *formlength = BigLong( length );
391         if ( length & 1 ) {
392                 *lbmptr++ = 0;          // pad chunk to even offset
393
394         }
395 //
396 // write output file
397 //
398         SaveFile( filename, lbm, lbmptr - lbm );
399         free( lbm );
400 }
401
402
403 /*
404    ============================================================================
405
406    LOAD PCX
407
408    ============================================================================
409  */
410
411 typedef struct
412 {
413         char manufacturer;
414         char version;
415         char encoding;
416         char bits_per_pixel;
417         unsigned short xmin,ymin,xmax,ymax;
418         unsigned short hres,vres;
419         unsigned char palette[48];
420         char reserved;
421         char color_planes;
422         unsigned short bytes_per_line;
423         unsigned short palette_type;
424         char filler[58];
425         unsigned char data;             // unbounded
426 } pcx_t;
427
428 /*
429    ==============
430    LoadPCX
431    ==============
432  */
433 void LoadPCX( char *filename, byte **pic, byte **palette, int *width, int *height ){
434         byte    *raw;
435         pcx_t   *pcx;
436         int x, y;
437         int len;
438         int dataByte, runLength;
439         byte    *out, *pix;
440
441         //
442         // load the file
443         //
444         len = LoadFile( filename, (void **)&raw );
445
446         //
447         // parse the PCX file
448         //
449         pcx = (pcx_t *)raw;
450         raw = &pcx->data;
451
452         pcx->xmin = LittleShort( pcx->xmin );
453         pcx->ymin = LittleShort( pcx->ymin );
454         pcx->xmax = LittleShort( pcx->xmax );
455         pcx->ymax = LittleShort( pcx->ymax );
456         pcx->hres = LittleShort( pcx->hres );
457         pcx->vres = LittleShort( pcx->vres );
458         pcx->bytes_per_line = LittleShort( pcx->bytes_per_line );
459         pcx->palette_type = LittleShort( pcx->palette_type );
460
461         if ( pcx->manufacturer != 0x0a
462                  || pcx->version != 5
463                  || pcx->encoding != 1
464                  || pcx->bits_per_pixel != 8
465                  || pcx->xmax >= 640
466                  || pcx->ymax >= 480 ) {
467                 Error( "Bad pcx file %s", filename );
468         }
469
470         if ( palette ) {
471                 *palette = malloc( 768 );
472                 memcpy( *palette, (byte *)pcx + len - 768, 768 );
473                 CorrectPalette( *palette );
474         }
475
476         if ( width ) {
477                 *width = pcx->xmax + 1;
478         }
479         if ( height ) {
480                 *height = pcx->ymax + 1;
481         }
482
483         if ( !pic ) {
484                 return;
485         }
486
487         out = malloc( ( pcx->ymax + 1 ) * ( pcx->xmax + 1 ) );
488         if ( !out ) {
489                 Error( "Skin_Cache: couldn't allocate" );
490         }
491
492         *pic = out;
493
494         pix = out;
495
496         for ( y = 0 ; y <= pcx->ymax ; y++, pix += pcx->xmax + 1 )
497         {
498                 for ( x = 0 ; x <= pcx->xmax ; )
499                 {
500                         dataByte = *raw++;
501
502                         if ( ( dataByte & 0xC0 ) == 0xC0 ) {
503                                 runLength = dataByte & 0x3F;
504                                 dataByte = *raw++;
505                         }
506                         else{
507                                 runLength = 1;
508                         }
509
510                         while ( runLength-- > 0 )
511                                 pix[x++] = dataByte;
512                 }
513
514         }
515
516         if ( raw - (byte *)pcx > len ) {
517                 Error( "PCX file %s was malformed", filename );
518         }
519
520         free( pcx );
521 }
522
523 /*
524    ==============
525    WritePCXfile
526    ==============
527  */
528
529 void StuffPackedByte( int curRepCount, byte curByte, byte** packPtr ){
530         byte* pack;
531
532         pack = *packPtr;
533
534         while ( curRepCount > 0 )
535         {
536                 if ( curRepCount == 1 ) {
537                         if ( ( curByte & 0xc0 ) != 0xc0 ) {
538                                 *pack++ = curByte;
539                         }
540                         else
541                         {
542                                 *pack++ = 0xc1;
543                                 *pack++ = curByte;
544                         }
545                         break;
546                 }
547                 if ( curRepCount < 0x0040 ) {
548                         *pack++ = ( 0x00c0 | curRepCount );
549                         curRepCount = 0;
550                 }
551                 else
552                 {
553                         *pack++ = 0xff;
554                         curRepCount -= 0x003f;
555                 }
556                 *pack++ = curByte;
557         }
558         *packPtr = pack;
559 }
560
561 void WritePCXfile( char *filename, byte *data,
562                                    int width, int height, byte *palette ){
563         int i, j, length;
564         pcx_t       *pcx;
565         byte        *pack;
566         byte curByte;
567         int curRepCount;
568
569         pcx = malloc( width * height * 2 + 1000 );
570         memset( pcx, 0, sizeof( *pcx ) );
571
572         pcx->manufacturer = 0x0a;   // PCX id
573         pcx->version = 5;           // 256 color
574         pcx->encoding = 1;      // RLE
575         pcx->bits_per_pixel = 8;        // 256 color
576         pcx->xmin = 0;
577         pcx->ymin = 0;
578         pcx->xmax = LittleShort( (short)( width - 1 ) );
579         pcx->ymax = LittleShort( (short)( height - 1 ) );
580         pcx->hres = LittleShort( (short)width );
581         pcx->vres = LittleShort( (short)height );
582         pcx->color_planes = 1;      // chunky image
583         pcx->bytes_per_line = LittleShort( (short)width );
584         pcx->palette_type = LittleShort( 1 );     // not a grey scale
585
586         // pack the image
587         pack = &pcx->data;
588
589 /*      for (i=0 ; i<height ; i++)
590     {
591         for (j=0 ; j<width ; j++)
592         {
593             if ( (*data & 0xc0) != 0xc0)
594    *pack++ = *data++;
595             else
596             {
597    *pack++ = 0xc1;
598    *pack++ = *data++;
599             }
600         }
601     }
602  */
603         for ( i = 0 ; i < height ; i++ )
604         {
605                 curByte = *data;
606                 curRepCount = 0;
607                 for ( j = 0 ; j < width ; j++ )
608                 {
609                         if ( *data == curByte ) {
610                                 curRepCount++;
611                                 data++;
612                                 continue;
613                         }
614                         StuffPackedByte( curRepCount, curByte, &pack );
615                         curByte = *data++;
616                         curRepCount = 1;
617                 }
618                 StuffPackedByte( curRepCount, curByte, &pack );
619         }
620         // write the palette
621         *pack++ = 0x0c; // palette ID byte
622         for ( i = 0 ; i < 768 ; i++ )
623                 *pack++ = *palette++;
624
625 // write output file
626         length = pack - (byte *)pcx;
627         SaveFile( filename, pcx, length );
628
629         free( pcx );
630 }
631
632
633 /*
634    ============================================================================
635
636    LOAD IMAGE
637
638    ============================================================================
639  */
640
641 /*
642    ==============
643    Load256Image
644
645    Will load either an lbm or pcx, depending on extension.
646    Any of the return pointers can be NULL if you don't want them.
647    ==============
648  */
649 void Load256Image( char *name, byte **pixels, byte **palette,
650                                    int *width, int *height ){
651         char ext[128];
652
653         ExtractFileExtension( name, ext );
654         if ( !Q_strcasecmp( ext, "lbm" ) ) {
655                 LoadLBM( name, pixels, palette );
656                 if ( width ) {
657                         *width = bmhd.w;
658                 }
659                 if ( height ) {
660                         *height = bmhd.h;
661                 }
662         }
663         else if ( !Q_strcasecmp( ext, "pcx" ) ) {
664                 LoadPCX( name, pixels, palette, width, height );
665         }
666         else{
667                 Error( "%s doesn't have a known image extension", name );
668         }
669 }
670
671
672 /*
673    ==============
674    Save256Image
675
676    Will save either an lbm or pcx, depending on extension.
677    ==============
678  */
679 void Save256Image( char *name, byte *pixels, byte *palette,
680                                    int width, int height ){
681         char ext[128];
682
683         ExtractFileExtension( name, ext );
684         if ( !Q_strcasecmp( ext, "lbm" ) ) {
685                 WriteLBMfile( name, pixels, width, height, palette );
686         }
687         else if ( !Q_strcasecmp( ext, "pcx" ) ) {
688                 WritePCXfile( name, pixels, width, height, palette );
689         }
690         else{
691                 Error( "%s doesn't have a known image extension", name );
692         }
693 }
694
695
696
697
698 /*
699    ============================================================================
700
701    TARGA IMAGE
702
703    ============================================================================
704  */
705
706 typedef struct _TargaHeader
707 {
708         unsigned char id_length, colormap_type, image_type;
709         unsigned short colormap_index, colormap_length;
710         unsigned char colormap_size;
711         unsigned short x_origin, y_origin, width, height;
712         unsigned char pixel_size, attributes;
713 } TargaHeader;
714
715 int fgetLittleShort( FILE *f ){
716         byte b1, b2;
717
718         b1 = fgetc( f );
719         b2 = fgetc( f );
720
721         return( (short)( b1 + ( b2 << 8 ) ) );
722 }
723
724 int fgetLittleLong( FILE *f ){
725         byte b1, b2, b3, b4;
726
727         b1 = fgetc( f );
728         b2 = fgetc( f );
729         b3 = fgetc( f );
730         b4 = fgetc( f );
731
732         return( b1 + ( b2 << 8 ) + ( b3 << 16 ) + ( b4 << 24 ) );
733 }
734
735
736 /*
737    =============
738    LoadTGA
739    =============
740  */
741 void LoadTGA( char *name, byte **pixels, int *width, int *height ){
742         int columns, rows, numPixels;
743         byte            *pixbuf;
744         byte            *rowBuf;
745         int row, column;
746         FILE            *fin;
747         byte            *targa_rgba;
748         TargaHeader targa_header;
749         unsigned char red, green, blue, alphabyte;
750         unsigned char packetHeader, packetSize, j;
751         int flip;
752         int mirror;
753         int rowOffset;
754         int pixDirection;
755
756         fin = fopen( name, "rb" );
757         if ( !fin ) {
758                 Error( "Couldn't read %s", name );
759         }
760
761         targa_header.id_length = fgetc( fin );
762         targa_header.colormap_type = fgetc( fin );
763         targa_header.image_type = fgetc( fin );
764
765         targa_header.colormap_index = fgetLittleShort( fin );
766         targa_header.colormap_length = fgetLittleShort( fin );
767         targa_header.colormap_size = fgetc( fin );
768         targa_header.x_origin = fgetLittleShort( fin );
769         targa_header.y_origin = fgetLittleShort( fin );
770         targa_header.width = fgetLittleShort( fin );
771         targa_header.height = fgetLittleShort( fin );
772         targa_header.pixel_size = fgetc( fin );
773         targa_header.attributes = fgetc( fin );
774         flip = ( targa_header.attributes & 0x020 ) == 0;
775         mirror = ( targa_header.attributes & 0x010 ) != 0;
776
777         if ( ( targa_header.image_type != 2 ) && ( targa_header.image_type != 10 ) ) {
778                 Error( "LoadTGA: Only type 2 and 10 targa RGB images supported\n" );
779         }
780
781         if ( targa_header.colormap_type || ( ( targa_header.pixel_size != 32 ) && ( targa_header.pixel_size != 24 ) ) ) {
782                 Error( "Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n" );
783         }
784
785         columns = targa_header.width;
786         rows = targa_header.height;
787         numPixels = columns * rows;
788
789         if ( width ) {
790                 *width = columns;
791         }
792         if ( height ) {
793                 *height = rows;
794         }
795
796         if ( !pixels ) {
797                 return;
798         }
799
800         targa_rgba = malloc( numPixels * 4 );
801         *pixels = targa_rgba;
802
803         if ( flip ) {
804                 pixbuf = targa_rgba + ( ( rows - 1 ) * columns * 4 );
805                 rowOffset = -columns * 4;
806         }
807         else
808         {
809                 pixbuf = targa_rgba;
810                 rowOffset = columns * 4;
811         }
812         if ( mirror ) {
813                 pixDirection = -4;
814                 pixbuf += ( ( columns - 1 ) * 4 );
815         }
816         else
817         {
818                 pixDirection = 4;
819         }
820
821         if ( targa_header.id_length ) {
822                 fseek( fin, targa_header.id_length, SEEK_CUR );  // skip TARGA image comment
823
824         }
825         if ( targa_header.image_type == 2 ) {                 // Uncompressed, RGB images
826                 for ( row = 0; row < rows; row++ )
827                 {
828                         rowBuf = pixbuf;
829                         for ( column = 0; column < columns; column++ )
830                         {
831                                 switch ( targa_header.pixel_size )
832                                 {
833                                 case 24:
834                                         blue = getc( fin );
835                                         green = getc( fin );
836                                         red = getc( fin );
837                                         rowBuf[0] = red;
838                                         rowBuf[1] = green;
839                                         rowBuf[2] = blue;
840                                         rowBuf[3] = 255;
841                                         rowBuf += pixDirection;
842                                         break;
843                                 case 32:
844                                         blue = getc( fin );
845                                         green = getc( fin );
846                                         red = getc( fin );
847                                         alphabyte = getc( fin );
848                                         rowBuf[0] = red;
849                                         rowBuf[1] = green;
850                                         rowBuf[2] = blue;
851                                         rowBuf[3] = alphabyte;
852                                         rowBuf += pixDirection;
853                                         break;
854                                 }
855                         }
856                         pixbuf += rowOffset;
857                 }
858         }
859         else if ( targa_header.image_type == 10 ) {        // Runlength encoded RGB images
860                 for ( row = 0; row < rows; row++ )
861                 {
862                         rowBuf = pixbuf;
863                         for ( column = 0; column < columns; )
864                         {
865                                 packetHeader = getc( fin );
866                                 packetSize = 1 + ( packetHeader & 0x7f );
867                                 if ( packetHeader & 0x80 ) {          // run-length packet
868                                         switch ( targa_header.pixel_size )
869                                         {
870                                         case 24:
871                                                 blue = getc( fin );
872                                                 green = getc( fin );
873                                                 red = getc( fin );
874                                                 alphabyte = 255;
875                                                 break;
876                                         case 32:
877                                                 blue = getc( fin );
878                                                 green = getc( fin );
879                                                 red = getc( fin );
880                                                 alphabyte = getc( fin );
881                                                 break;
882                                         }
883
884                                         for ( j = 0; j < packetSize; j++ )
885                                         {
886                                                 rowBuf[0] = red;
887                                                 rowBuf[1] = green;
888                                                 rowBuf[2] = blue;
889                                                 rowBuf[3] = alphabyte;
890                                                 rowBuf += pixDirection;
891                                                 column++;
892                                                 if ( column == columns ) {             // run spans across rows
893                                                         column = 0;
894                                                         row++;
895                                                         if ( row >= rows ) {
896                                                                 goto breakOut;
897                                                         }
898                                                         pixbuf += rowOffset;
899                                                         rowBuf = pixbuf;
900                                                 }
901                                         }
902                                 }
903                                 else
904                                 {                                       // non run-length packet
905                                         for ( j = 0; j < packetSize; j++ )
906                                         {
907                                                 switch ( targa_header.pixel_size )
908                                                 {
909                                                 case 24:
910                                                         blue = getc( fin );
911                                                         green = getc( fin );
912                                                         red = getc( fin );
913                                                         rowBuf[0] = red;
914                                                         rowBuf[1] = green;
915                                                         rowBuf[2] = blue;
916                                                         rowBuf[3] = 255;
917                                                         rowBuf += pixDirection;
918                                                         break;
919                                                 case 32:
920                                                         blue = getc( fin );
921                                                         green = getc( fin );
922                                                         red = getc( fin );
923                                                         alphabyte = getc( fin );
924                                                         rowBuf[0] = red;
925                                                         rowBuf[1] = green;
926                                                         rowBuf[2] = blue;
927                                                         rowBuf[3] = alphabyte;
928                                                         rowBuf += pixDirection;
929                                                         break;
930                                                 }
931                                                 column++;
932                                                 if ( column == columns ) {    // pixel packet run spans across rows
933                                                         column = 0;
934                                                         row++;
935                                                         if ( row >= rows ) {
936                                                                 goto breakOut;
937                                                         }
938                                                         pixbuf += rowOffset;
939                                                         rowBuf = pixbuf;
940                                                 }
941                                         }
942                                 }
943                         }
944 breakOut:;
945                         pixbuf += rowOffset;
946                 }
947         }
948         fclose( fin );
949 }
950
951 void MergeAlpha( byte *pix, byte *alpha, byte *pal, byte **out, int width, int height ){
952         int size, i;
953         byte    *data, *src, *srca;
954
955         size = width * height;
956         data = malloc( size * 4 );
957         if ( !data ) {
958                 Error( "Could not allocate memory for true color image" );
959         }
960
961         *out = data;
962         src = pix;
963         srca = alpha;
964
965         for ( i = 0; i < size; i++, src++, srca++ )
966         {
967                 *data++ = pal[*src * 3 + 0];      // r
968                 *data++ = pal[*src * 3 + 1];      // g
969                 *data++ = pal[*src * 3 + 2];      // b
970                 *data++ = *srca;                  // a
971         }
972         free( pix );
973         free( alpha );
974         free( pal );
975 }
976
977 /*
978    ==============
979    LoadAnyImage
980
981    Return Value:
982     false: paletted texture
983     true:  true color RGBA image (no palette)
984    ==============
985  */
986 qboolean LoadAnyImage( char *name, byte **pixels, byte **palette, int *width, int *height ){
987         char ext[128];
988         int len;
989         int alpha_width, alpha_height;
990         char alpha_name[128];
991         byte    *alpha_pixels;
992
993         ExtractFileExtension( name, ext );
994
995         if ( palette ) {
996                 *palette = NULL;
997         }
998
999         if ( !Q_strcasecmp( ext, "lbm" ) ) {
1000                 LoadLBM( name, pixels, palette );
1001                 if ( width ) {
1002                         *width = bmhd.w;
1003                 }
1004                 if ( height ) {
1005                         *height = bmhd.h;
1006                 }
1007                 return false;
1008         }
1009         else if ( !Q_strcasecmp( ext, "pcx" ) ) {
1010                 len = strlen( name );
1011                 strcpy( alpha_name, name );
1012                 strcpy( &alpha_name[len - 4], "_a.pcx" );                 // Alpha map name (may not exist)
1013
1014                 if ( FileExists( alpha_name ) ) {
1015                         LoadPCX( name, pixels, palette, width, height );                         // Load in image
1016                         LoadPCX( alpha_name, &alpha_pixels, NULL, &alpha_width, &alpha_height ); // Load in alpha map
1017                         if ( ( *width != alpha_width ) || ( *height != alpha_height ) ) {
1018                                 Error( "Alpha image dimensions not equal to graphic image dimensions" );
1019                         }
1020                         MergeAlpha( *pixels, alpha_pixels, *palette, pixels, *width, *height );
1021                         *palette = NULL; //Merge Frees pal
1022                         return true;
1023                 }
1024                 else
1025                 {
1026                         LoadPCX( name, pixels, palette, width, height );         // Load in image
1027                         return false;
1028                 }
1029         }
1030         else if ( !Q_strcasecmp( ext, "tga" ) ) {
1031                 LoadTGA( name, pixels, width, height );
1032                 if ( palette ) {
1033                         *palette = NULL;
1034                 }
1035
1036                 return true;
1037         }
1038         else{
1039                 Error( "%s doesn't have a known image extension", name );
1040         }
1041
1042         return false;
1043 }