2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
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.
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.
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
28 int fgetLittleShort (FILE *f)
35 return (short)(b1 + b2*256);
38 int fgetLittleLong (FILE *f)
47 return b1 + (b2<<8) + (b3<<16) + (b4<<24);
50 int bufLittleShort (byte *buf, int len, int *pos)
55 Error ("Unexpected buffer end");
57 b1 = buf[*pos]; *pos += 1;
58 b2 = buf[*pos]; *pos += 1;
60 return (short)(b1 + b2*256);
63 int bufLittleLong (byte *buf, int len, int *pos)
68 Error ("Unexpected buffer end");
70 b1 = buf[*pos]; *pos += 1;
71 b2 = buf[*pos]; *pos += 1;
72 b3 = buf[*pos]; *pos += 1;
73 b4 = buf[*pos]; *pos += 1;
75 return b1 + (b2<<8) + (b3<<16) + (b4<<24);
80 ============================================================================
84 ============================================================================
88 typedef unsigned char UBYTE;
89 //conflicts with windows typedef short WORD;
90 typedef unsigned short UWORD;
115 UWORD transparentColor;
116 UBYTE xAspect,yAspect;
117 short pageWidth,pageHeight;
120 extern bmhd_t bmhd; // will be in native byte order
124 #define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24))
125 #define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24))
126 #define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24))
127 #define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24))
128 #define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24))
129 #define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24))
147 Source must be evenly aligned!
150 byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth)
163 rept = (rept^0xff)+2;
165 memset(unpacked,b,rept);
168 else if (rept < 0x80)
171 memcpy(unpacked,source,rept);
176 rept = 0; // rept of 0x80 is NOP
180 } while (count<bpwidth);
183 Error ("Decompression exceeded width!\n");
195 void LoadLBM (const char *filename, byte **picture, byte **palette)
197 byte *LBMbuffer, *picbuffer, *cmapbuffer;
199 byte *LBM_P, *LBMEND_P;
203 int formtype,formlength;
204 int chunktype,chunklength;
206 // qiet compiler warnings
213 LoadFile (filename, (void **)&LBMbuffer);
216 // parse the LBM header
219 if ( *(int *)LBMbuffer != LittleLong(FORMID) )
220 Error ("No FORM ID at start of file!\n");
223 formlength = BigLong( *(int *)LBM_P );
225 LBMEND_P = LBM_P + Align(formlength);
227 formtype = LittleLong(*(int *)LBM_P);
229 if (formtype != ILBMID && formtype != PBMID)
230 Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff
231 ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff);
239 while (LBM_P < LBMEND_P)
241 chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24);
243 chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24);
249 memcpy (&bmhd,LBM_P,sizeof(bmhd));
250 bmhd.w = BigShort(bmhd.w);
251 bmhd.h = BigShort(bmhd.h);
252 bmhd.x = BigShort(bmhd.x);
253 bmhd.y = BigShort(bmhd.y);
254 bmhd.pageWidth = BigShort(bmhd.pageWidth);
255 bmhd.pageHeight = BigShort(bmhd.pageHeight);
259 cmapbuffer = safe_malloc (768);
260 memset (cmapbuffer, 0, 768);
261 memcpy (cmapbuffer, LBM_P, chunklength);
267 pic_p = picbuffer = safe_malloc (bmhd.w*bmhd.h);
268 if (formtype == PBMID)
273 for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
275 if (bmhd.compression == cm_rle1)
276 body_p = LBMRLEDecompress ((byte *)body_p
278 else if (bmhd.compression == cm_none)
280 memcpy (pic_p,body_p,bmhd.w);
281 body_p += Align(bmhd.w);
291 Error ("%s is an interlaced LBM, not packed", filename);
296 LBM_P += Align(chunklength);
301 *picture = picbuffer;
304 *palette = cmapbuffer;
309 ============================================================================
313 ============================================================================
321 void WriteLBMfile (const char *filename, byte *data,
322 int width, int height, byte *palette)
325 int *formlength, *bmhdlength, *cmaplength, *bodylength;
329 lbm = lbmptr = safe_malloc (width*height+1000);
339 formlength = (int*)lbmptr;
340 lbmptr+=4; // leave space for length
355 bmhdlength = (int *)lbmptr;
356 lbmptr+=4; // leave space for length
358 memset (&basebmhd,0,sizeof(basebmhd));
359 basebmhd.w = BigShort((short)width);
360 basebmhd.h = BigShort((short)height);
361 basebmhd.nPlanes = BigShort(8);
362 basebmhd.xAspect = BigShort(5);
363 basebmhd.yAspect = BigShort(6);
364 basebmhd.pageWidth = BigShort((short)width);
365 basebmhd.pageHeight = BigShort((short)height);
367 memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
368 lbmptr += sizeof(basebmhd);
370 length = lbmptr-(byte *)bmhdlength-4;
371 *bmhdlength = BigLong(length);
373 *lbmptr++ = 0; // pad chunk to even offset
383 cmaplength = (int *)lbmptr;
384 lbmptr+=4; // leave space for length
386 memcpy (lbmptr,palette,768);
389 length = lbmptr-(byte *)cmaplength-4;
390 *cmaplength = BigLong(length);
392 *lbmptr++ = 0; // pad chunk to even offset
402 bodylength = (int *)lbmptr;
403 lbmptr+=4; // leave space for length
405 memcpy (lbmptr,data,width*height);
406 lbmptr += width*height;
408 length = lbmptr-(byte *)bodylength-4;
409 *bodylength = BigLong(length);
411 *lbmptr++ = 0; // pad chunk to even offset
416 length = lbmptr-(byte *)formlength-4;
417 *formlength = BigLong(length);
419 *lbmptr++ = 0; // pad chunk to even offset
424 SaveFile (filename, lbm, lbmptr-lbm);
430 ============================================================================
434 ============================================================================
443 unsigned short xmin,ymin,xmax,ymax;
444 unsigned short hres,vres;
445 unsigned char palette[48];
448 unsigned short bytes_per_line;
449 unsigned short palette_type;
451 unsigned char data; // unbounded
462 #define DECODEPCX( b, d, r ) d=*b++;if((d&0xC0)==0xC0){r=d&0x3F;d=*b++;}else{r=1;}
464 void LoadPCX( const char *filename, byte **pic, byte **palette, int *width, int *height )
470 int dataByte, runLength;
475 len = vfsLoadFile (filename, (void **)&raw, 0);
477 Error( "LoadPCX: Couldn't read %s", filename );
480 /* parse the PCX file */
484 pcx->xmin = LittleShort(pcx->xmin);
485 pcx->ymin = LittleShort(pcx->ymin);
486 pcx->xmax = LittleShort(pcx->xmax);
487 pcx->ymax = LittleShort(pcx->ymax);
488 pcx->hres = LittleShort(pcx->hres);
489 pcx->vres = LittleShort(pcx->vres);
490 pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
491 pcx->palette_type = LittleShort(pcx->palette_type);
493 if (pcx->manufacturer != 0x0a
495 || pcx->encoding != 1
496 || pcx->bits_per_pixel != 8
499 Error ("Bad pcx file %s", filename);
503 *palette = safe_malloc(768);
504 memcpy (*palette, (byte *)pcx + len - 768, 768);
508 *width = pcx->xmax+1;
510 *height = pcx->ymax+1;
515 out = safe_malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
517 Error( "LoadPCX: couldn't allocate");
522 /* RR2DO2: pcx fix */
523 lsize = pcx->color_planes * pcx->bytes_per_line;
525 /* go scanline by scanline */
526 for( y = 0; y <= pcx->ymax; y++, pix += pcx->xmax + 1 )
529 for( x=0; x <= pcx->xmax; )
532 DECODEPCX( raw, dataByte, runLength );
533 while( runLength-- > 0 )
534 pix[ x++ ] = dataByte;
537 /* RR2DO2: discard any other data */
540 DECODEPCX( raw, dataByte, runLength );
543 while( runLength-- > 0 )
548 if( raw - (byte *) pcx > len)
549 Error( "PCX file %s was malformed", filename );
560 void WritePCXfile (const char *filename, byte *data,
561 int width, int height, byte *palette)
567 pcx = safe_malloc (width*height*2+1000);
568 memset (pcx, 0, sizeof(*pcx));
570 pcx->manufacturer = 0x0a; // PCX id
571 pcx->version = 5; // 256 color
572 pcx->encoding = 1; // uncompressed
573 pcx->bits_per_pixel = 8; // 256 color
576 pcx->xmax = LittleShort((short)(width-1));
577 pcx->ymax = LittleShort((short)(height-1));
578 pcx->hres = LittleShort((short)width);
579 pcx->vres = LittleShort((short)height);
580 pcx->color_planes = 1; // chunky image
581 pcx->bytes_per_line = LittleShort((short)width);
582 pcx->palette_type = LittleShort(1); // not a grey scale
587 for (i=0 ; i<height ; i++)
589 for (j=0 ; j<width ; j++)
591 if ( (*data & 0xc0) != 0xc0)
602 *pack++ = 0x0c; // palette ID byte
603 for (i=0 ; i<768 ; i++)
604 *pack++ = *palette++;
607 length = pack - (byte *)pcx;
608 SaveFile (filename, pcx, length);
614 ============================================================================
618 ============================================================================
624 // we can't just use these structures, because
625 // compiler structure alignment will not be portable
626 // on this unaligned stuff
628 typedef struct tagBITMAPFILEHEADER { // bmfh
636 typedef struct tagBITMAPINFOHEADER{ // bmih
644 LONG biXPelsPerMeter;
645 LONG biYPelsPerMeter;
647 DWORD biClrImportant;
650 typedef struct tagBITMAPINFO { // bmi
651 BITMAPINFOHEADER bmiHeader;
652 RGBQUAD bmiColors[1];
655 typedef struct tagBITMAPCOREHEADER { // bmch
663 typedef struct _BITMAPCOREINFO { // bmci
664 BITMAPCOREHEADER bmciHeader;
665 RGBTRIPLE bmciColors[1];
675 void LoadBMP (const char *filename, byte **pic, byte **palette, int *width, int *height)
686 byte bcPalette[1024];
691 len = vfsLoadFile (filename, (void **)&in, 0);
694 Error ("Couldn't read %s", filename);
697 i = bufLittleShort (in, len, &pos);
698 if (i != 'B' + ('M'<<8) ) {
699 Error ("%s is not a bmp file", filename);
702 bfSize = bufLittleLong (in, len, &pos);
703 bufLittleShort(in, len, &pos);
704 bufLittleShort(in, len, &pos);
705 bfOffBits = bufLittleLong (in, len, &pos);
707 // the size will tell us if it is a
708 // bitmapinfo or a bitmapcore
709 structSize = bufLittleLong (in, len, &pos);
710 if (structSize == 40)
713 bcWidth = bufLittleLong(in, len, &pos);
714 bcHeight= bufLittleLong(in, len, &pos);
715 bcPlanes = bufLittleShort(in, len, &pos);
716 bcBitCount = bufLittleShort(in, len, &pos);
722 memcpy (bcPalette, in+pos, 1024);
724 *palette = safe_malloc(768);
726 for (i = 0 ; i < 256 ; i++)
728 (*palette)[i * 3 + 0] = bcPalette[i * 4 + 2];
729 (*palette)[i * 3 + 1] = bcPalette[i * 4 + 1];
730 (*palette)[i * 3 + 2] = bcPalette[i * 4 + 0];
734 else if (structSize == 12)
737 bcWidth = bufLittleShort(in, len, &pos);
738 bcHeight= bufLittleShort(in, len, &pos);
739 bcPlanes = bufLittleShort(in, len, &pos);
740 bcBitCount = bufLittleShort(in, len, &pos);
744 memcpy (bcPalette, in+pos, 768);
746 *palette = safe_malloc(768);
748 for (i = 0 ; i < 256 ; i++) {
749 (*palette)[i * 3 + 0] = bcPalette[i * 3 + 2];
750 (*palette)[i * 3 + 1] = bcPalette[i * 3 + 1];
751 (*palette)[i * 3 + 2] = bcPalette[i * 3 + 0];
755 Error ("%s had strange struct size", filename);
759 Error ("%s was not a single plane image", filename);
762 if (bcBitCount != 8) {
763 Error ("%s was not an 8 bit image", filename);
767 bcHeight = -bcHeight;
783 out = safe_malloc ( bcWidth * bcHeight );
788 for (i = 0 ; i < bcHeight ; i++) {
789 memcpy (out + bcWidth * (bcHeight - 1 - i), in+pos, bcWidth);
793 memcpy (out, in+pos, bcWidth*bcHeight);
794 pos += bcWidth*bcHeight;
802 ============================================================================
806 ============================================================================
813 Will load either an lbm or pcx, depending on extension.
814 Any of the return pointers can be NULL if you don't want them.
817 void Load256Image (const char *name, byte **pixels, byte **palette, int *width, int *height)
821 ExtractFileExtension (name, ext);
822 if (!Q_stricmp (ext, "lbm"))
824 LoadLBM (name, pixels, palette);
830 else if (!Q_stricmp (ext, "pcx"))
832 LoadPCX (name, pixels, palette, width, height);
834 else if (!Q_stricmp (ext, "bmp"))
836 LoadBMP (name, pixels, palette, width, height);
839 Error ("%s doesn't have a known image extension", name);
847 Will save either an lbm or pcx, depending on extension.
850 void Save256Image (const char *name, byte *pixels, byte *palette,
851 int width, int height)
855 ExtractFileExtension (name, ext);
856 if (!Q_stricmp (ext, "lbm"))
858 WriteLBMfile (name, pixels, width, height, palette);
860 else if (!Q_stricmp (ext, "pcx"))
862 WritePCXfile (name, pixels, width, height, palette);
865 Error ("%s doesn't have a known image extension", name);
872 ============================================================================
876 ============================================================================
879 typedef struct _TargaHeader {
880 unsigned char id_length, colormap_type, image_type;
881 unsigned short colormap_index, colormap_length;
882 unsigned char colormap_size;
883 unsigned short x_origin, y_origin, width, height;
884 unsigned char pixel_size, attributes;
892 void LoadTGABuffer ( byte *buffer, byte **pic, int *width, int *height)
894 int columns, rows, numPixels;
898 TargaHeader targa_header;
905 targa_header.id_length = *buf_p++;
906 targa_header.colormap_type = *buf_p++;
907 targa_header.image_type = *buf_p++;
909 targa_header.colormap_index = LittleShort ( *(short *)buf_p );
911 targa_header.colormap_length = LittleShort ( *(short *)buf_p );
913 targa_header.colormap_size = *buf_p++;
914 targa_header.x_origin = LittleShort ( *(short *)buf_p );
916 targa_header.y_origin = LittleShort ( *(short *)buf_p );
918 targa_header.width = LittleShort ( *(short *)buf_p );
920 targa_header.height = LittleShort ( *(short *)buf_p );
922 targa_header.pixel_size = *buf_p++;
923 targa_header.attributes = *buf_p++;
925 if (targa_header.image_type!=2
926 && targa_header.image_type!=10
927 && targa_header.image_type != 3 )
929 Error("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
932 if ( targa_header.colormap_type != 0 )
934 Error("LoadTGA: colormaps not supported\n" );
937 if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 )
939 Error("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
942 columns = targa_header.width;
943 rows = targa_header.height;
944 numPixels = columns * rows;
951 targa_rgba = safe_malloc (numPixels*4);
954 if (targa_header.id_length != 0)
955 buf_p += targa_header.id_length; // skip TARGA image comment
957 if ( targa_header.image_type==2 || targa_header.image_type == 3 )
959 // Uncompressed RGB or gray scale image
960 for(row=rows-1; row>=0; row--)
962 pixbuf = targa_rgba + row*columns*4;
963 for(column=0; column<columns; column++)
965 unsigned char red,green,blue,alphabyte;
966 switch (targa_header.pixel_size)
992 alphabyte = *buf_p++;
996 *pixbuf++ = alphabyte;
999 //Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
1005 else if (targa_header.image_type==10) { // Runlength encoded RGB images
1006 unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
1013 for(row=rows-1; row>=0; row--) {
1014 pixbuf = targa_rgba + row*columns*4;
1015 for(column=0; column<columns; ) {
1016 packetHeader= *buf_p++;
1017 packetSize = 1 + (packetHeader & 0x7f);
1018 if (packetHeader & 0x80) { // run-length packet
1019 switch (targa_header.pixel_size) {
1030 alphabyte = *buf_p++;
1033 //Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
1037 for(j=0;j<packetSize;j++) {
1041 *pixbuf++=alphabyte;
1043 if (column==columns) { // run spans across rows
1049 pixbuf = targa_rgba + row*columns*4;
1053 else { // non run-length packet
1054 for(j=0;j<packetSize;j++) {
1055 switch (targa_header.pixel_size) {
1069 alphabyte = *buf_p++;
1073 *pixbuf++ = alphabyte;
1076 //Sysprintf("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
1080 if (column==columns) { // pixel packet run spans across rows
1086 pixbuf = targa_rgba + row*columns*4;
1095 // vertically flipped
1096 if ( (targa_header.attributes & (1<<5)) ) {
1098 for (row = 0; row < .5f * rows; row++)
1100 for (column = 0; column < columns; column++)
1102 flip = *( (int*)targa_rgba + row * columns + column);
1103 *( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column );
1104 *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip;
1119 void LoadTGA (const char *name, byte **pixels, int *width, int *height)
1126 nLen = vfsLoadFile ( ( char * ) name, (void **)&buffer, 0);
1129 Error ("Couldn't read %s", name);
1132 LoadTGABuffer(buffer, pixels, width, height);
1142 void WriteTGA (const char *filename, byte *data, int width, int height) {
1148 buffer = safe_malloc(width*height*4 + 18);
1149 memset (buffer, 0, 18);
1150 buffer[2] = 2; // uncompressed type
1151 buffer[12] = width&255;
1152 buffer[13] = width>>8;
1153 buffer[14] = height&255;
1154 buffer[15] = height>>8;
1155 buffer[16] = 32; // pixel size
1158 c = 18 + width * height * 4;
1159 for (i=18 ; i<c ; i+=4)
1161 buffer[i] = data[i-18+2]; // blue
1162 buffer[i+1] = data[i-18+1]; // green
1163 buffer[i+2] = data[i-18+0]; // red
1164 buffer[i+3] = data[i-18+3]; // alpha
1167 f = fopen (filename, "wb");
1168 fwrite (buffer, 1, c, f);
1175 ============================================================================
1179 ============================================================================
1186 Any of the return pointers can be NULL if you don't want them.
1189 void Load32BitImage (const char *name, unsigned **pixels, int *width, int *height)
1199 ExtractFileExtension (name, ext);
1200 if (!Q_stricmp (ext, "tga")) {
1201 LoadTGA (name, (byte **)pixels, width, height);
1203 Load256Image (name, &pixels8, &palette, width, height);
1207 size = *width * *height;
1208 pixels32 = safe_malloc(size * 4);
1209 *pixels = (unsigned *)pixels32;
1210 for (i = 0 ; i < size ; i++) {
1212 pixels32[i*4 + 0] = palette[ v * 3 + 0 ];
1213 pixels32[i*4 + 1] = palette[ v * 3 + 1 ];
1214 pixels32[i*4 + 2] = palette[ v * 3 + 2 ];
1215 pixels32[i*4 + 3] = 0xff;