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