2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\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
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
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
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
39 void CorrectPalette(byte *pal)
\r
43 p = (paletteRGB_t *)pal;
\r
44 // Color 0 always transparent
\r
51 ============================================================================
\r
55 ============================================================================
\r
59 typedef unsigned char UBYTE;
\r
60 //conflicts with windows typedef short WORD;
\r
61 typedef unsigned short UWORD;
\r
86 UWORD transparentColor;
\r
87 UBYTE xAspect,yAspect;
\r
88 short pageWidth,pageHeight;
\r
91 extern bmhd_t bmhd; // will be in native byte order
\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
118 Source must be evenly aligned!
\r
121 byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth)
\r
134 rept = (rept^0xff)+2;
\r
136 memset(unpacked,b,rept);
\r
139 else if (rept < 0x80)
\r
142 memcpy(unpacked,source,rept);
\r
147 rept = 0; // rept of 0x80 is NOP
\r
151 } while (count<bpwidth);
\r
154 Error ("Decompression exceeded width!\n");
\r
166 void LoadLBM (char *filename, byte **picture, byte **palette)
\r
168 byte *LBMbuffer, *picbuffer, *cmapbuffer;
\r
170 byte *LBM_P, *LBMEND_P;
\r
174 int formtype,formlength;
\r
175 int chunktype,chunklength;
\r
177 // qiet compiler warnings
\r
184 LoadFile (filename, (void **)&LBMbuffer);
\r
187 // parse the LBM header
\r
190 if ( *(int *)LBMbuffer != LittleLong(FORMID) )
\r
191 Error ("No FORM ID at start of file!\n");
\r
194 formlength = BigLong( *(int *)LBM_P );
\r
196 LBMEND_P = LBM_P + Align(formlength);
\r
198 formtype = LittleLong(*(int *)LBM_P);
\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
210 while (LBM_P < LBMEND_P)
\r
212 chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24);
\r
214 chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24);
\r
217 switch ( chunktype )
\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
230 cmapbuffer = malloc (768);
\r
231 memset (cmapbuffer, 0, 768);
\r
232 memcpy (cmapbuffer, LBM_P, chunklength);
\r
233 CorrectPalette(cmapbuffer);
\r
239 pic_p = picbuffer = malloc (bmhd.w*bmhd.h);
\r
240 if (formtype == PBMID)
\r
245 for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
\r
247 if (bmhd.compression == cm_rle1)
\r
248 body_p = LBMRLEDecompress ((byte *)body_p
\r
250 else if (bmhd.compression == cm_none)
\r
252 memcpy (pic_p,body_p,bmhd.w);
\r
253 body_p += Align(bmhd.w);
\r
263 Error ("%s is an interlaced LBM, not packed", filename);
\r
268 LBM_P += Align(chunklength);
\r
273 *picture = picbuffer;
\r
276 *palette = cmapbuffer;
\r
281 ============================================================================
\r
285 ============================================================================
\r
293 void WriteLBMfile (char *filename, byte *data,
\r
294 int width, int height, byte *palette)
\r
296 byte *lbm, *lbmptr;
\r
297 int *formlength, *bmhdlength, *cmaplength, *bodylength;
\r
301 lbm = lbmptr = malloc (width*height+1000);
\r
311 formlength = (int*)lbmptr;
\r
312 lbmptr+=4; // leave space for length
\r
327 bmhdlength = (int *)lbmptr;
\r
328 lbmptr+=4; // leave space for length
\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
339 memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
\r
340 lbmptr += sizeof(basebmhd);
\r
342 length = lbmptr-(byte *)bmhdlength-4;
\r
343 *bmhdlength = BigLong(length);
\r
345 *lbmptr++ = 0; // pad chunk to even offset
\r
355 cmaplength = (int *)lbmptr;
\r
356 lbmptr+=4; // leave space for length
\r
358 memcpy (lbmptr,palette,768);
\r
361 length = lbmptr-(byte *)cmaplength-4;
\r
362 *cmaplength = BigLong(length);
\r
364 *lbmptr++ = 0; // pad chunk to even offset
\r
374 bodylength = (int *)lbmptr;
\r
375 lbmptr+=4; // leave space for length
\r
377 memcpy (lbmptr,data,width*height);
\r
378 lbmptr += width*height;
\r
380 length = lbmptr-(byte *)bodylength-4;
\r
381 *bodylength = BigLong(length);
\r
383 *lbmptr++ = 0; // pad chunk to even offset
\r
388 length = lbmptr-(byte *)formlength-4;
\r
389 *formlength = BigLong(length);
\r
391 *lbmptr++ = 0; // pad chunk to even offset
\r
394 // write output file
\r
396 SaveFile (filename, lbm, lbmptr-lbm);
\r
402 ============================================================================
\r
406 ============================================================================
\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
420 unsigned short bytes_per_line;
\r
421 unsigned short palette_type;
\r
423 unsigned char data; // unbounded
\r
431 void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
\r
437 int dataByte, runLength;
\r
443 len = LoadFile (filename, (void **)&raw);
\r
446 // parse the PCX file
\r
448 pcx = (pcx_t *)raw;
\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
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
470 *palette = malloc(768);
\r
471 memcpy (*palette, (byte *)pcx + len - 768, 768);
\r
472 CorrectPalette(*palette);
\r
476 *width = pcx->xmax+1;
\r
478 *height = pcx->ymax+1;
\r
483 out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
\r
485 Error ("Skin_Cache: couldn't allocate");
\r
491 for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
\r
493 for (x=0 ; x<=pcx->xmax ; )
\r
497 if((dataByte & 0xC0) == 0xC0)
\r
499 runLength = dataByte & 0x3F;
\r
505 while(runLength-- > 0)
\r
506 pix[x++] = dataByte;
\r
511 if ( raw - (byte *)pcx > len)
\r
512 Error ("PCX file %s was malformed", filename);
\r
523 void StuffPackedByte(int curRepCount, byte curByte, byte** packPtr)
\r
529 while(curRepCount > 0)
\r
531 if (curRepCount == 1)
\r
533 if ((curByte & 0xc0) != 0xc0)
\r
544 if (curRepCount < 0x0040)
\r
546 *pack++ = (0x00c0 | curRepCount);
\r
552 curRepCount -= 0x003f;
\r
559 void WritePCXfile (char *filename, byte *data,
\r
560 int width, int height, byte *palette)
\r
568 pcx = malloc (width*height*2+1000);
\r
569 memset (pcx, 0, sizeof(*pcx));
\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
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
588 /* for (i=0 ; i<height ; i++)
\r
590 for (j=0 ; j<width ; j++)
\r
592 if ( (*data & 0xc0) != 0xc0)
\r
602 for (i=0 ; i<height ; i++)
\r
606 for (j=0 ; j<width ; j++)
\r
608 if (*data == curByte)
\r
614 StuffPackedByte(curRepCount, curByte, &pack);
\r
618 StuffPackedByte(curRepCount, curByte, &pack);
\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
625 // write output file
\r
626 length = pack - (byte *)pcx;
\r
627 SaveFile (filename, pcx, length);
\r
634 ============================================================================
\r
638 ============================================================================
\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
649 void Load256Image (char *name, byte **pixels, byte **palette,
\r
650 int *width, int *height)
\r
654 ExtractFileExtension (name, ext);
\r
655 if (!Q_strcasecmp (ext, "lbm"))
\r
657 LoadLBM (name, pixels, palette);
\r
663 else if (!Q_strcasecmp (ext, "pcx"))
\r
665 LoadPCX (name, pixels, palette, width, height);
\r
668 Error ("%s doesn't have a known image extension", name);
\r
676 Will save either an lbm or pcx, depending on extension.
\r
679 void Save256Image (char *name, byte *pixels, byte *palette,
\r
680 int width, int height)
\r
684 ExtractFileExtension (name, ext);
\r
685 if (!Q_strcasecmp (ext, "lbm"))
\r
687 WriteLBMfile (name, pixels, width, height, palette);
\r
689 else if (!Q_strcasecmp (ext, "pcx"))
\r
691 WritePCXfile (name, pixels, width, height, palette);
\r
694 Error ("%s doesn't have a known image extension", name);
\r
701 ============================================================================
\r
705 ============================================================================
\r
708 typedef struct _TargaHeader
\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
717 int fgetLittleShort (FILE *f)
\r
724 return((short)(b1 + (b2 << 8)));
\r
727 int fgetLittleLong (FILE *f)
\r
729 byte b1, b2, b3, b4;
\r
736 return(b1 + (b2 << 8) + (b3 << 16) + (b4 << 24));
\r
745 void LoadTGA(char *name, byte **pixels, int *width, int *height)
\r
747 int columns, rows, numPixels;
\r
753 TargaHeader targa_header;
\r
754 unsigned char red, green, blue, alphabyte;
\r
755 unsigned char packetHeader, packetSize, j;
\r
761 fin = fopen(name, "rb");
\r
763 Error ("Couldn't read %s", name);
\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
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
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
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
787 columns = targa_header.width;
\r
788 rows = targa_header.height;
\r
789 numPixels = columns * rows;
\r
799 targa_rgba = malloc(numPixels * 4);
\r
800 *pixels = targa_rgba;
\r
804 pixbuf = targa_rgba + ((rows - 1) * columns * 4);
\r
805 rowOffset = -columns * 4;
\r
809 pixbuf = targa_rgba;
\r
810 rowOffset = columns * 4;
\r
815 pixbuf += ((columns - 1) * 4);
\r
822 if (targa_header.id_length)
\r
823 fseek(fin, targa_header.id_length, SEEK_CUR); // skip TARGA image comment
\r
825 if (targa_header.image_type == 2)
\r
826 { // Uncompressed, RGB images
\r
827 for(row = 0; row < rows; row++)
\r
830 for(column = 0; column < columns; column++)
\r
832 switch (targa_header.pixel_size)
\r
842 rowBuf += pixDirection;
\r
848 alphabyte = getc(fin);
\r
852 rowBuf[3] = alphabyte;
\r
853 rowBuf += pixDirection;
\r
857 pixbuf += rowOffset;
\r
860 else if(targa_header.image_type == 10)
\r
861 { // Runlength encoded RGB images
\r
862 for(row = 0; row < rows; row++)
\r
865 for(column = 0; column < columns; )
\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
883 alphabyte = getc(fin);
\r
887 for(j = 0; j < packetSize; j++)
\r
892 rowBuf[3] = alphabyte;
\r
893 rowBuf += pixDirection;
\r
895 if(column == columns)
\r
896 { // run spans across rows
\r
901 pixbuf += rowOffset;
\r
907 { // non run-length packet
\r
908 for(j = 0; j < packetSize; j++)
\r
910 switch (targa_header.pixel_size)
\r
920 rowBuf += pixDirection;
\r
926 alphabyte = getc(fin);
\r
930 rowBuf[3] = alphabyte;
\r
931 rowBuf += pixDirection;
\r
935 if (column == columns)
\r
936 { // pixel packet run spans across rows
\r
941 pixbuf += rowOffset;
\r
948 pixbuf += rowOffset;
\r
954 void MergeAlpha(byte *pix, byte *alpha, byte *pal, byte **out, int width, int height)
\r
957 byte *data, *src, *srca;
\r
959 size = width * height;
\r
960 data = malloc(size * 4);
\r
962 Error("Could not allocate memory for true color image");
\r
968 for(i = 0; i < size; i++, src++, srca++)
\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
985 false: paletted texture
\r
986 true: true color RGBA image (no palette)
\r
989 qboolean LoadAnyImage (char *name, byte **pixels, byte **palette, int *width, int *height)
\r
993 int alpha_width, alpha_height;
\r
994 char alpha_name[128];
\r
995 byte *alpha_pixels;
\r
997 ExtractFileExtension (name, ext);
\r
1004 if (!Q_strcasecmp (ext, "lbm"))
\r
1006 LoadLBM (name, pixels, palette);
\r
1013 else if (!Q_strcasecmp (ext, "pcx"))
\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
1019 if(FileExists(alpha_name))
\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
1025 Error("Alpha image dimensions not equal to graphic image dimensions");
\r
1027 MergeAlpha(*pixels, alpha_pixels, *palette, pixels, *width, *height);
\r
1028 *palette = NULL;//Merge Frees pal
\r
1033 LoadPCX (name, pixels, palette, width, height); // Load in image
\r
1037 else if (!Q_strcasecmp (ext, "tga"))
\r
1039 LoadTGA(name, pixels, width, height);
\r
1048 Error ("%s doesn't have a known image extension", name);
\r