]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/common/imagelib.c
set eol-style
[xonotic/netradiant.git] / tools / quake3 / common / imagelib.c
1 /*
2 Copyright (C) 1999-2007 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 // imagelib.c
23
24 #include "cmdlib.h"
25 #include "imagelib.h"
26 #include "vfs.h"
27
28 int fgetLittleShort (FILE *f)
29 {
30         byte    b1, b2;
31
32         b1 = fgetc(f);
33         b2 = fgetc(f);
34
35         return (short)(b1 + b2*256);
36 }
37
38 int fgetLittleLong (FILE *f)
39 {
40         byte    b1, b2, b3, b4;
41
42         b1 = fgetc(f);
43         b2 = fgetc(f);
44         b3 = fgetc(f);
45         b4 = fgetc(f);
46
47         return b1 + (b2<<8) + (b3<<16) + (b4<<24);
48 }
49
50 int bufLittleShort (byte *buf, int len, int *pos)
51 {
52   byte  b1, b2;
53
54   if ((len - *pos) < 2)
55     Error ("Unexpected buffer end");
56
57   b1 = buf[*pos]; *pos += 1;
58   b2 = buf[*pos]; *pos += 1;
59
60   return (short)(b1 + b2*256);
61 }
62
63 int bufLittleLong (byte *buf, int len, int *pos)
64 {
65   byte b1, b2, b3, b4;
66
67   if ((len - *pos) < 4)
68     Error ("Unexpected buffer end");
69
70   b1 = buf[*pos]; *pos += 1;
71   b2 = buf[*pos]; *pos += 1;
72   b3 = buf[*pos]; *pos += 1;
73   b4 = buf[*pos]; *pos += 1;
74
75   return b1 + (b2<<8) + (b3<<16) + (b4<<24);
76 }
77
78
79 /*
80 ============================================================================
81
82                                                 LBM STUFF
83
84 ============================================================================
85 */
86
87
88 typedef unsigned char   UBYTE;
89 //conflicts with windows typedef short                  WORD;
90 typedef unsigned short  UWORD;
91 typedef long                    LONG;
92
93 typedef enum
94 {
95         ms_none,
96         ms_mask,
97         ms_transcolor,
98         ms_lasso
99 } mask_t;
100
101 typedef enum
102 {
103         cm_none,
104         cm_rle1
105 } compress_t;
106
107 typedef struct
108 {
109         UWORD           w,h;
110         short           x,y;
111         UBYTE           nPlanes;
112         UBYTE           masking;
113         UBYTE           compression;
114         UBYTE           pad1;
115         UWORD           transparentColor;
116         UBYTE           xAspect,yAspect;
117         short           pageWidth,pageHeight;
118 } bmhd_t;
119
120 extern  bmhd_t  bmhd;                                           // will be in native byte order
121
122
123
124 #define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24))
125 #define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24))
126 #define PBMID  ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24))
127 #define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24))
128 #define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24))
129 #define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24))
130
131
132 bmhd_t  bmhd;
133
134 int    Align (int l)
135 {
136         if (l&1)
137                 return l+1;
138         return l;
139 }
140
141
142
143 /*
144 ================
145 LBMRLEdecompress
146
147 Source must be evenly aligned!
148 ================
149 */
150 byte  *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth)
151 {
152         int     count;
153         byte    b,rept;
154
155         count = 0;
156
157         do
158         {
159                 rept = *source++;
160
161                 if (rept > 0x80)
162                 {
163                         rept = (rept^0xff)+2;
164                         b = *source++;
165                         memset(unpacked,b,rept);
166                         unpacked += rept;
167                 }
168                 else if (rept < 0x80)
169                 {
170                         rept++;
171                         memcpy(unpacked,source,rept);
172                         unpacked += rept;
173                         source += rept;
174                 }
175                 else
176                         rept = 0;               // rept of 0x80 is NOP
177
178                 count += rept;
179
180         } while (count<bpwidth);
181
182         if (count>bpwidth)
183                 Error ("Decompression exceeded width!\n");
184
185
186         return source;
187 }
188
189
190 /*
191 =================
192 LoadLBM
193 =================
194 */
195 void LoadLBM (const char *filename, byte **picture, byte **palette)
196 {
197         byte    *LBMbuffer, *picbuffer, *cmapbuffer;
198         int             y;
199         byte    *LBM_P, *LBMEND_P;
200         byte    *pic_p;
201         byte    *body_p;
202
203         int    formtype,formlength;
204         int    chunktype,chunklength;
205
206 // qiet compiler warnings
207         picbuffer = NULL;
208         cmapbuffer = NULL;
209
210 //
211 // load the LBM
212 //
213         LoadFile (filename, (void **)&LBMbuffer);
214
215 //
216 // parse the LBM header
217 //
218         LBM_P = LBMbuffer;
219         if ( *(int *)LBMbuffer != LittleLong(FORMID) )
220            Error ("No FORM ID at start of file!\n");
221
222         LBM_P += 4;
223         formlength = BigLong( *(int *)LBM_P );
224         LBM_P += 4;
225         LBMEND_P = LBM_P + Align(formlength);
226
227         formtype = LittleLong(*(int *)LBM_P);
228
229         if (formtype != ILBMID && formtype != PBMID)
230                 Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff
231                 ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff);
232
233         LBM_P += 4;
234
235 //
236 // parse chunks
237 //
238
239         while (LBM_P < LBMEND_P)
240         {
241                 chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24);
242                 LBM_P += 4;
243                 chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24);
244                 LBM_P += 4;
245
246                 switch ( chunktype )
247                 {
248                 case BMHDID:
249                         memcpy (&bmhd,LBM_P,sizeof(bmhd));
250                         bmhd.w = BigShort(bmhd.w);
251                         bmhd.h = BigShort(bmhd.h);
252                         bmhd.x = BigShort(bmhd.x);
253                         bmhd.y = BigShort(bmhd.y);
254                         bmhd.pageWidth = BigShort(bmhd.pageWidth);
255                         bmhd.pageHeight = BigShort(bmhd.pageHeight);
256                         break;
257
258                 case CMAPID:
259                         cmapbuffer = safe_malloc (768);
260                         memset (cmapbuffer, 0, 768);
261                         memcpy (cmapbuffer, LBM_P, chunklength);
262                         break;
263
264                 case BODYID:
265                         body_p = LBM_P;
266
267                         pic_p = picbuffer = safe_malloc (bmhd.w*bmhd.h);
268                         if (formtype == PBMID)
269                         {
270                         //
271                         // unpack PBM
272                         //
273                                 for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
274                                 {
275                                         if (bmhd.compression == cm_rle1)
276                                                 body_p = LBMRLEDecompress ((byte *)body_p
277                                                 , pic_p , bmhd.w);
278                                         else if (bmhd.compression == cm_none)
279                                         {
280                                                 memcpy (pic_p,body_p,bmhd.w);
281                                                 body_p += Align(bmhd.w);
282                                         }
283                                 }
284
285                         }
286                         else
287                         {
288                         //
289                         // unpack ILBM
290                         //
291                                 Error ("%s is an interlaced LBM, not packed", filename);
292                         }
293                         break;
294                 }
295
296                 LBM_P += Align(chunklength);
297         }
298
299         free (LBMbuffer);
300
301         *picture = picbuffer;
302
303         if (palette)
304                 *palette = cmapbuffer;
305 }
306
307
308 /*
309 ============================================================================
310
311                                                         WRITE LBM
312
313 ============================================================================
314 */
315
316 /*
317 ==============
318 WriteLBMfile
319 ==============
320 */
321 void WriteLBMfile (const char *filename, byte *data,
322                                    int width, int height, byte *palette)
323 {
324         byte    *lbm, *lbmptr;
325         int    *formlength, *bmhdlength, *cmaplength, *bodylength;
326         int    length;
327         bmhd_t  basebmhd;
328
329         lbm = lbmptr = safe_malloc (width*height+1000);
330
331 //
332 // start FORM
333 //
334         *lbmptr++ = 'F';
335         *lbmptr++ = 'O';
336         *lbmptr++ = 'R';
337         *lbmptr++ = 'M';
338
339         formlength = (int*)lbmptr;
340         lbmptr+=4;                      // leave space for length
341
342         *lbmptr++ = 'P';
343         *lbmptr++ = 'B';
344         *lbmptr++ = 'M';
345         *lbmptr++ = ' ';
346
347 //
348 // write BMHD
349 //
350         *lbmptr++ = 'B';
351         *lbmptr++ = 'M';
352         *lbmptr++ = 'H';
353         *lbmptr++ = 'D';
354
355         bmhdlength = (int *)lbmptr;
356         lbmptr+=4;                      // leave space for length
357
358         memset (&basebmhd,0,sizeof(basebmhd));
359         basebmhd.w = BigShort((short)width);
360         basebmhd.h = BigShort((short)height);
361         basebmhd.nPlanes = BigShort(8);
362         basebmhd.xAspect = BigShort(5);
363         basebmhd.yAspect = BigShort(6);
364         basebmhd.pageWidth = BigShort((short)width);
365         basebmhd.pageHeight = BigShort((short)height);
366
367         memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
368         lbmptr += sizeof(basebmhd);
369
370         length = lbmptr-(byte *)bmhdlength-4;
371         *bmhdlength = BigLong(length);
372         if (length&1)
373                 *lbmptr++ = 0;          // pad chunk to even offset
374
375 //
376 // write CMAP
377 //
378         *lbmptr++ = 'C';
379         *lbmptr++ = 'M';
380         *lbmptr++ = 'A';
381         *lbmptr++ = 'P';
382
383         cmaplength = (int *)lbmptr;
384         lbmptr+=4;                      // leave space for length
385
386         memcpy (lbmptr,palette,768);
387         lbmptr += 768;
388
389         length = lbmptr-(byte *)cmaplength-4;
390         *cmaplength = BigLong(length);
391         if (length&1)
392                 *lbmptr++ = 0;          // pad chunk to even offset
393
394 //
395 // write BODY
396 //
397         *lbmptr++ = 'B';
398         *lbmptr++ = 'O';
399         *lbmptr++ = 'D';
400         *lbmptr++ = 'Y';
401
402         bodylength = (int *)lbmptr;
403         lbmptr+=4;                      // leave space for length
404
405         memcpy (lbmptr,data,width*height);
406         lbmptr += width*height;
407
408         length = lbmptr-(byte *)bodylength-4;
409         *bodylength = BigLong(length);
410         if (length&1)
411                 *lbmptr++ = 0;          // pad chunk to even offset
412
413 //
414 // done
415 //
416         length = lbmptr-(byte *)formlength-4;
417         *formlength = BigLong(length);
418         if (length&1)
419                 *lbmptr++ = 0;          // pad chunk to even offset
420
421 //
422 // write output file
423 //
424         SaveFile (filename, lbm, lbmptr-lbm);
425         free (lbm);
426 }
427
428
429 /*
430 ============================================================================
431
432 LOAD PCX
433
434 ============================================================================
435 */
436
437 typedef struct
438 {
439     char        manufacturer;
440     char        version;
441     char        encoding;
442     char        bits_per_pixel;
443     unsigned short      xmin,ymin,xmax,ymax;
444     unsigned short      hres,vres;
445     unsigned char       palette[48];
446     char        reserved;
447     char        color_planes;
448     unsigned short      bytes_per_line;
449     unsigned short      palette_type;
450     char        filler[58];
451     unsigned char       data;                   // unbounded
452 } pcx_t;
453
454
455 /*
456 ==============
457 LoadPCX
458 ==============
459 */
460
461 /* RR2DO2 */
462 #define DECODEPCX( b, d, r ) d=*b++;if((d&0xC0)==0xC0){r=d&0x3F;d=*b++;}else{r=1;}
463
464 void LoadPCX( const char *filename, byte **pic, byte **palette, int *width, int *height )
465 {
466         byte    *raw;
467         pcx_t   *pcx;
468         int             x, y, lsize;
469         int             len;
470         int             dataByte, runLength;
471         byte    *out, *pix;
472         
473
474         /* load the file */
475         len = vfsLoadFile (filename, (void **)&raw, 0);
476     if( len == -1 ) 
477                 Error( "LoadPCX: Couldn't read %s", filename );
478
479         
480         /* parse the PCX file */
481         pcx = (pcx_t *)raw;
482         raw = &pcx->data;
483
484         pcx->xmin = LittleShort(pcx->xmin);
485         pcx->ymin = LittleShort(pcx->ymin);
486         pcx->xmax = LittleShort(pcx->xmax);
487         pcx->ymax = LittleShort(pcx->ymax);
488         pcx->hres = LittleShort(pcx->hres);
489         pcx->vres = LittleShort(pcx->vres);
490         pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
491         pcx->palette_type = LittleShort(pcx->palette_type);
492
493         if (pcx->manufacturer != 0x0a
494                 || pcx->version != 5
495                 || pcx->encoding != 1
496                 || pcx->bits_per_pixel != 8
497                 || pcx->xmax >= 640
498                 || pcx->ymax >= 480)
499                 Error ("Bad pcx file %s", filename);
500         
501         if (palette)
502         {
503                 *palette = safe_malloc(768);
504                 memcpy (*palette, (byte *)pcx + len - 768, 768);
505         }
506
507         if (width)
508                 *width = pcx->xmax+1;
509         if (height)
510                 *height = pcx->ymax+1;
511
512         if (!pic)
513                 return;
514
515         out = safe_malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
516         if (!out)
517                 Error( "LoadPCX: couldn't allocate");
518
519         *pic = out;
520         pix = out;
521         
522         /* RR2DO2: pcx fix  */
523         lsize = pcx->color_planes * pcx->bytes_per_line;
524         
525         /* go scanline by scanline */
526         for( y = 0; y <= pcx->ymax; y++, pix += pcx->xmax + 1 )
527         {
528                 /* do a scanline */
529                 for( x=0; x <= pcx->xmax; )
530                 {
531                         /* RR2DO2 */
532                         DECODEPCX( raw, dataByte, runLength );
533                         while( runLength-- > 0 )
534                                 pix[ x++ ] = dataByte;
535                 }
536
537                 /* RR2DO2: discard any other data */
538                 while( x < lsize )
539                 {
540                         DECODEPCX( raw, dataByte, runLength );
541                         x++;
542                 }
543                 while( runLength-- > 0 )
544                         x++;
545         }
546         
547         /* validity check */
548         if( raw - (byte *) pcx > len)
549                 Error( "PCX file %s was malformed", filename );
550         free( pcx );
551 }
552
553
554
555 /* 
556 ============== 
557 WritePCXfile 
558 ============== 
559 */ 
560 void WritePCXfile (const char *filename, byte *data, 
561                                    int width, int height, byte *palette) 
562 {
563         int             i, j, length;
564         pcx_t   *pcx;
565         byte            *pack;
566           
567         pcx = safe_malloc (width*height*2+1000);
568         memset (pcx, 0, sizeof(*pcx));
569
570         pcx->manufacturer = 0x0a;       // PCX id
571         pcx->version = 5;                       // 256 color
572         pcx->encoding = 1;              // uncompressed
573         pcx->bits_per_pixel = 8;                // 256 color
574         pcx->xmin = 0;
575         pcx->ymin = 0;
576         pcx->xmax = LittleShort((short)(width-1));
577         pcx->ymax = LittleShort((short)(height-1));
578         pcx->hres = LittleShort((short)width);
579         pcx->vres = LittleShort((short)height);
580         pcx->color_planes = 1;          // chunky image
581         pcx->bytes_per_line = LittleShort((short)width);
582         pcx->palette_type = LittleShort(1);             // not a grey scale
583
584         // pack the image
585         pack = &pcx->data;
586         
587         for (i=0 ; i<height ; i++)
588         {
589                 for (j=0 ; j<width ; j++)
590                 {
591                         if ( (*data & 0xc0) != 0xc0)
592                                 *pack++ = *data++;
593                         else
594                         {
595                                 *pack++ = 0xc1;
596                                 *pack++ = *data++;
597                         }
598                 }
599         }
600                         
601         // write the palette
602         *pack++ = 0x0c; // palette ID byte
603         for (i=0 ; i<768 ; i++)
604                 *pack++ = *palette++;
605                 
606 // write output file 
607         length = pack - (byte *)pcx;
608         SaveFile (filename, pcx, length);
609
610         free (pcx);
611
612  
613 /*
614 ============================================================================
615
616 LOAD BMP
617
618 ============================================================================
619 */
620
621
622 /*
623
624 // we can't just use these structures, because
625 // compiler structure alignment will not be portable
626 // on this unaligned stuff
627
628 typedef struct tagBITMAPFILEHEADER { // bmfh 
629         WORD    bfType;                         // BM
630         DWORD   bfSize; 
631         WORD    bfReserved1; 
632         WORD    bfReserved2; 
633         DWORD   bfOffBits; 
634 } BITMAPFILEHEADER; 
635  
636 typedef struct tagBITMAPINFOHEADER{ // bmih 
637    DWORD  biSize; 
638    LONG   biWidth; 
639    LONG   biHeight; 
640    WORD   biPlanes; 
641    WORD   biBitCount 
642    DWORD  biCompression; 
643    DWORD  biSizeImage; 
644    LONG   biXPelsPerMeter; 
645    LONG   biYPelsPerMeter; 
646    DWORD  biClrUsed; 
647    DWORD  biClrImportant; 
648 } BITMAPINFOHEADER; 
649  
650 typedef struct tagBITMAPINFO { // bmi 
651    BITMAPINFOHEADER bmiHeader; 
652    RGBQUAD          bmiColors[1]; 
653 } BITMAPINFO; 
654
655 typedef struct tagBITMAPCOREHEADER { // bmch 
656         DWORD   bcSize; 
657         WORD    bcWidth; 
658         WORD    bcHeight; 
659         WORD    bcPlanes; 
660         WORD    bcBitCount; 
661 } BITMAPCOREHEADER; 
662  
663 typedef struct _BITMAPCOREINFO {    // bmci 
664         BITMAPCOREHEADER  bmciHeader; 
665         RGBTRIPLE         bmciColors[1]; 
666 } BITMAPCOREINFO; 
667  
668 */
669
670 /*
671 ==============
672 LoadBMP
673 ==============
674 */
675 void LoadBMP (const char *filename, byte **pic, byte **palette, int *width, int *height)
676 {
677   byte  *out;
678   int           i;
679   int           bfSize; 
680   int           bfOffBits; 
681   int           structSize;
682   int           bcWidth; 
683   int     bcHeight; 
684   int       bcPlanes; 
685   int           bcBitCount; 
686   byte  bcPalette[1024];
687   qboolean      flipped;
688   byte *in;
689   int len, pos = 0;
690
691   len = vfsLoadFile (filename, (void **)&in, 0);
692   if (len == -1) 
693   {
694     Error ("Couldn't read %s", filename);
695   }
696
697   i = bufLittleShort (in, len, &pos);
698   if (i != 'B' + ('M'<<8) ) {
699     Error ("%s is not a bmp file", filename);
700   }
701
702   bfSize = bufLittleLong (in, len, &pos);
703   bufLittleShort(in, len, &pos);
704   bufLittleShort(in, len, &pos);
705   bfOffBits = bufLittleLong (in, len, &pos);
706
707   // the size will tell us if it is a
708   // bitmapinfo or a bitmapcore
709   structSize = bufLittleLong (in, len, &pos);
710   if (structSize == 40)
711   {
712     // bitmapinfo
713     bcWidth = bufLittleLong(in, len, &pos); 
714     bcHeight= bufLittleLong(in, len, &pos); 
715     bcPlanes = bufLittleShort(in, len, &pos); 
716     bcBitCount = bufLittleShort(in, len, &pos); 
717
718     pos += 24;
719
720     if (palette)
721     {
722       memcpy (bcPalette, in+pos, 1024);
723       pos += 1024;
724       *palette = safe_malloc(768);
725
726       for (i = 0 ; i < 256 ; i++)
727       {
728         (*palette)[i * 3 + 0] = bcPalette[i * 4 + 2];
729         (*palette)[i * 3 + 1] = bcPalette[i * 4 + 1];
730         (*palette)[i * 3 + 2] = bcPalette[i * 4 + 0];
731       }
732     }
733   }
734   else if (structSize == 12)
735   {
736     // bitmapcore
737     bcWidth = bufLittleShort(in, len, &pos); 
738     bcHeight= bufLittleShort(in, len, &pos); 
739     bcPlanes = bufLittleShort(in, len, &pos); 
740     bcBitCount = bufLittleShort(in, len, &pos); 
741
742     if (palette)
743     {
744       memcpy (bcPalette, in+pos, 768);
745       pos += 768;
746       *palette = safe_malloc(768);
747
748       for (i = 0 ; i < 256 ; i++) {
749         (*palette)[i * 3 + 0] = bcPalette[i * 3 + 2];
750         (*palette)[i * 3 + 1] = bcPalette[i * 3 + 1];
751         (*palette)[i * 3 + 2] = bcPalette[i * 3 + 0];
752       }
753     }
754   } else {
755     Error ("%s had strange struct size", filename);
756   }
757
758   if (bcPlanes != 1) {
759     Error ("%s was not a single plane image", filename);
760   }
761
762   if (bcBitCount != 8) {
763     Error ("%s was not an 8 bit image", filename);
764   }
765
766   if (bcHeight < 0) {
767     bcHeight = -bcHeight;
768     flipped = qtrue;
769   } else {
770     flipped = qfalse;
771   }
772
773   if (width)
774     *width = bcWidth;
775   if (height)
776     *height = bcHeight;
777
778   if (!pic) {
779     free (in);
780     return;
781   }
782
783   out = safe_malloc ( bcWidth * bcHeight );
784   *pic = out;
785   pos = bfOffBits;
786
787   if (flipped) {
788     for (i = 0 ; i < bcHeight ; i++) {
789       memcpy (out + bcWidth * (bcHeight - 1 - i), in+pos, bcWidth);
790       pos += bcWidth;
791     }
792   } else {
793     memcpy (out, in+pos, bcWidth*bcHeight);
794     pos += bcWidth*bcHeight;
795   }
796
797   free (in);
798 }
799
800
801 /*
802 ============================================================================
803
804 LOAD IMAGE
805
806 ============================================================================
807 */
808
809 /*
810 ==============
811 Load256Image
812
813 Will load either an lbm or pcx, depending on extension.
814 Any of the return pointers can be NULL if you don't want them.
815 ==============
816 */
817 void Load256Image (const char *name, byte **pixels, byte **palette, int *width, int *height)
818 {
819   char ext[128];
820
821   ExtractFileExtension (name, ext);
822   if (!Q_stricmp (ext, "lbm"))
823   {
824     LoadLBM (name, pixels, palette);
825     if (width)
826       *width = bmhd.w;
827     if (height)
828       *height = bmhd.h;
829   }
830   else if (!Q_stricmp (ext, "pcx"))
831   {
832     LoadPCX (name, pixels, palette, width, height);
833   }
834   else if (!Q_stricmp (ext, "bmp"))
835   {
836     LoadBMP (name, pixels, palette, width, height);
837   }
838   else
839     Error ("%s doesn't have a known image extension", name);
840 }
841
842
843 /*
844 ==============
845 Save256Image
846
847 Will save either an lbm or pcx, depending on extension.
848 ==============
849 */
850 void Save256Image (const char *name, byte *pixels, byte *palette,
851                                    int width, int height)
852 {
853         char    ext[128];
854
855         ExtractFileExtension (name, ext);
856         if (!Q_stricmp (ext, "lbm"))
857         {
858                 WriteLBMfile (name, pixels, width, height, palette);
859         }
860         else if (!Q_stricmp (ext, "pcx"))
861         {
862                 WritePCXfile (name, pixels, width, height, palette);
863         }
864         else
865                 Error ("%s doesn't have a known image extension", name);
866 }
867
868
869
870
871 /*
872 ============================================================================
873
874 TARGA IMAGE
875
876 ============================================================================
877 */
878
879 typedef struct _TargaHeader {
880         unsigned char   id_length, colormap_type, image_type;
881         unsigned short  colormap_index, colormap_length;
882         unsigned char   colormap_size;
883         unsigned short  x_origin, y_origin, width, height;
884         unsigned char   pixel_size, attributes;
885 } TargaHeader;
886
887 /*
888 =============
889 LoadTGABuffer
890 =============
891 */
892 void LoadTGABuffer ( byte *buffer, byte **pic, int *width, int *height)
893 {
894         int             columns, rows, numPixels;
895         byte    *pixbuf;
896         int             row, column;
897         byte    *buf_p;
898         TargaHeader     targa_header;
899         byte            *targa_rgba;
900
901         *pic = NULL;
902
903         buf_p = buffer;
904
905         targa_header.id_length = *buf_p++;
906         targa_header.colormap_type = *buf_p++;
907         targa_header.image_type = *buf_p++;
908         
909         targa_header.colormap_index = LittleShort ( *(short *)buf_p );
910         buf_p += 2;
911         targa_header.colormap_length = LittleShort ( *(short *)buf_p );
912         buf_p += 2;
913         targa_header.colormap_size = *buf_p++;
914         targa_header.x_origin = LittleShort ( *(short *)buf_p );
915         buf_p += 2;
916         targa_header.y_origin = LittleShort ( *(short *)buf_p );
917         buf_p += 2;
918         targa_header.width = LittleShort ( *(short *)buf_p );
919         buf_p += 2;
920         targa_header.height = LittleShort ( *(short *)buf_p );
921         buf_p += 2;
922         targa_header.pixel_size = *buf_p++;
923         targa_header.attributes = *buf_p++;
924
925         if (targa_header.image_type!=2 
926                 && targa_header.image_type!=10
927                 && targa_header.image_type != 3 ) 
928         {
929                 Error("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
930         }
931
932         if ( targa_header.colormap_type != 0 )
933         {
934                 Error("LoadTGA: colormaps not supported\n" );
935         }
936
937         if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 )
938         {
939                 Error("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
940         }
941
942         columns = targa_header.width;
943         rows = targa_header.height;
944         numPixels = columns * rows;
945
946         if (width)
947                 *width = columns;
948         if (height)
949                 *height = rows;
950
951         targa_rgba = safe_malloc (numPixels*4);
952         *pic = targa_rgba;
953
954         if (targa_header.id_length != 0)
955                 buf_p += targa_header.id_length;  // skip TARGA image comment
956         
957         if ( targa_header.image_type==2 || targa_header.image_type == 3 )
958         { 
959                 // Uncompressed RGB or gray scale image
960                 for(row=rows-1; row>=0; row--) 
961                 {
962                         pixbuf = targa_rgba + row*columns*4;
963                         for(column=0; column<columns; column++) 
964                         {
965                                 unsigned char red,green,blue,alphabyte;
966                                 switch (targa_header.pixel_size) 
967                                 {
968                                         
969                                 case 8:
970                                         blue = *buf_p++;
971                                         green = blue;
972                                         red = blue;
973                                         *pixbuf++ = red;
974                                         *pixbuf++ = green;
975                                         *pixbuf++ = blue;
976                                         *pixbuf++ = 255;
977                                         break;
978
979                                 case 24:
980                                         blue = *buf_p++;
981                                         green = *buf_p++;
982                                         red = *buf_p++;
983                                         *pixbuf++ = red;
984                                         *pixbuf++ = green;
985                                         *pixbuf++ = blue;
986                                         *pixbuf++ = 255;
987                                         break;
988                                 case 32:
989                                         blue = *buf_p++;
990                                         green = *buf_p++;
991                                         red = *buf_p++;
992                                         alphabyte = *buf_p++;
993                                         *pixbuf++ = red;
994                                         *pixbuf++ = green;
995                                         *pixbuf++ = blue;
996                                         *pixbuf++ = alphabyte;
997                                         break;
998                                 default:
999                                         //Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
1000                                         break;
1001                                 }
1002                         }
1003                 }
1004         }
1005         else if (targa_header.image_type==10) {   // Runlength encoded RGB images
1006                 unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
1007
1008                 red = 0;
1009                 green = 0;
1010                 blue = 0;
1011                 alphabyte = 0xff;
1012
1013                 for(row=rows-1; row>=0; row--) {
1014                         pixbuf = targa_rgba + row*columns*4;
1015                         for(column=0; column<columns; ) {
1016                                 packetHeader= *buf_p++;
1017                                 packetSize = 1 + (packetHeader & 0x7f);
1018                                 if (packetHeader & 0x80) {        // run-length packet
1019                                         switch (targa_header.pixel_size) {
1020                                                 case 24:
1021                                                                 blue = *buf_p++;
1022                                                                 green = *buf_p++;
1023                                                                 red = *buf_p++;
1024                                                                 alphabyte = 255;
1025                                                                 break;
1026                                                 case 32:
1027                                                                 blue = *buf_p++;
1028                                                                 green = *buf_p++;
1029                                                                 red = *buf_p++;
1030                                                                 alphabyte = *buf_p++;
1031                                                                 break;
1032                                                 default:
1033                                                         //Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
1034                                                         break;
1035                                         }
1036         
1037                                         for(j=0;j<packetSize;j++) {
1038                                                 *pixbuf++=red;
1039                                                 *pixbuf++=green;
1040                                                 *pixbuf++=blue;
1041                                                 *pixbuf++=alphabyte;
1042                                                 column++;
1043                                                 if (column==columns) { // run spans across rows
1044                                                         column=0;
1045                                                         if (row>0)
1046                                                                 row--;
1047                                                         else
1048                                                                 goto breakOut;
1049                                                         pixbuf = targa_rgba + row*columns*4;
1050                                                 }
1051                                         }
1052                                 }
1053                                 else {                            // non run-length packet
1054                                         for(j=0;j<packetSize;j++) {
1055                                                 switch (targa_header.pixel_size) {
1056                                                         case 24:
1057                                                                         blue = *buf_p++;
1058                                                                         green = *buf_p++;
1059                                                                         red = *buf_p++;
1060                                                                         *pixbuf++ = red;
1061                                                                         *pixbuf++ = green;
1062                                                                         *pixbuf++ = blue;
1063                                                                         *pixbuf++ = 255;
1064                                                                         break;
1065                                                         case 32:
1066                                                                         blue = *buf_p++;
1067                                                                         green = *buf_p++;
1068                                                                         red = *buf_p++;
1069                                                                         alphabyte = *buf_p++;
1070                                                                         *pixbuf++ = red;
1071                                                                         *pixbuf++ = green;
1072                                                                         *pixbuf++ = blue;
1073                                                                         *pixbuf++ = alphabyte;
1074                                                                         break;
1075                                                         default:
1076                                                                 //Sysprintf("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
1077                                                                 break;
1078                                                 }
1079                                                 column++;
1080                                                 if (column==columns) { // pixel packet run spans across rows
1081                                                         column=0;
1082                                                         if (row>0)
1083                                                                 row--;
1084                                                         else
1085                                                                 goto breakOut;
1086                                                         pixbuf = targa_rgba + row*columns*4;
1087                                                 }                                               
1088                                         }
1089                                 }
1090                         }
1091                         breakOut:;
1092                 }
1093         }
1094
1095         // vertically flipped
1096         if ( (targa_header.attributes & (1<<5)) ) {
1097                 int flip;
1098                 for (row = 0; row < .5f * rows; row++)
1099                 {
1100                         for (column = 0; column < columns; column++)
1101                         {
1102                                 flip = *( (int*)targa_rgba + row * columns + column);
1103                                 *( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column );
1104                                 *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip;
1105                         }
1106                 }
1107         }
1108
1109         //free(buffer);
1110 }
1111
1112
1113
1114 /*
1115 =============
1116 LoadTGA
1117 =============
1118 */
1119 void LoadTGA (const char *name, byte **pixels, int *width, int *height)
1120 {
1121         byte                    *buffer;
1122   int nLen;
1123         //
1124         // load the file
1125         //
1126         nLen = vfsLoadFile ( ( char * ) name, (void **)&buffer, 0);
1127         if (nLen == -1) 
1128   {
1129                 Error ("Couldn't read %s", name);
1130   }
1131
1132   LoadTGABuffer(buffer, pixels, width, height);
1133
1134 }
1135
1136
1137 /*
1138 ================
1139 WriteTGA
1140 ================
1141 */
1142 void WriteTGA (const char *filename, byte *data, int width, int height) {
1143         byte    *buffer;
1144         int             i;
1145         int             c;
1146         FILE    *f;
1147
1148         buffer = safe_malloc(width*height*4 + 18);
1149         memset (buffer, 0, 18);
1150         buffer[2] = 2;          // uncompressed type
1151         buffer[12] = width&255;
1152         buffer[13] = width>>8;
1153         buffer[14] = height&255;
1154         buffer[15] = height>>8;
1155         buffer[16] = 32;        // pixel size
1156
1157         // swap rgb to bgr
1158         c = 18 + width * height * 4;
1159         for (i=18 ; i<c ; i+=4)
1160         {
1161                 buffer[i] = data[i-18+2];               // blue
1162                 buffer[i+1] = data[i-18+1];             // green
1163                 buffer[i+2] = data[i-18+0];             // red
1164                 buffer[i+3] = data[i-18+3];             // alpha
1165         }
1166
1167         f = fopen (filename, "wb");
1168         fwrite (buffer, 1, c, f);
1169         fclose (f);
1170
1171         free (buffer);
1172 }
1173
1174 /*
1175 ============================================================================
1176
1177 LOAD32BITIMAGE
1178
1179 ============================================================================
1180 */
1181
1182 /*
1183 ==============
1184 Load32BitImage
1185
1186 Any of the return pointers can be NULL if you don't want them.
1187 ==============
1188 */
1189 void Load32BitImage (const char *name, unsigned **pixels,  int *width, int *height)
1190 {
1191         char    ext[128];
1192         byte    *palette;
1193         byte    *pixels8;
1194         byte    *pixels32;
1195         int             size;
1196         int             i;
1197         int             v;
1198
1199         ExtractFileExtension (name, ext);
1200         if (!Q_stricmp (ext, "tga")) {
1201                 LoadTGA (name, (byte **)pixels, width, height);
1202         } else {
1203                 Load256Image (name, &pixels8, &palette, width, height);
1204                 if (!pixels) {
1205                         return;
1206                 }
1207                 size = *width * *height;
1208                 pixels32 = safe_malloc(size * 4);
1209                 *pixels = (unsigned *)pixels32;
1210                 for (i = 0 ; i < size ; i++) {
1211                         v = pixels8[i];
1212                         pixels32[i*4 + 0] = palette[ v * 3 + 0 ];
1213                         pixels32[i*4 + 1] = palette[ v * 3 + 1 ];
1214                         pixels32[i*4 + 2] = palette[ v * 3 + 2 ];
1215                         pixels32[i*4 + 3] = 0xff;
1216                 }
1217         }
1218 }
1219
1220