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