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
30 ============================================================================
\r
34 ============================================================================
\r
38 typedef unsigned char UBYTE;
\r
39 //conflicts with windows typedef short WORD;
\r
40 typedef unsigned short UWORD;
\r
65 UWORD transparentColor;
\r
66 UBYTE xAspect,yAspect;
\r
67 short pageWidth,pageHeight;
\r
70 extern bmhd_t bmhd; // will be in native byte order
\r
74 #define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24))
\r
75 #define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24))
\r
76 #define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24))
\r
77 #define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24))
\r
78 #define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24))
\r
79 #define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24))
\r
97 Source must be evenly aligned!
\r
100 byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth)
\r
113 rept = (rept^0xff)+2;
\r
115 memset(unpacked,b,rept);
\r
118 else if (rept < 0x80)
\r
121 memcpy(unpacked,source,rept);
\r
126 rept = 0; // rept of 0x80 is NOP
\r
130 } while (count<bpwidth);
\r
133 Error ("Decompression exceeded width!\n");
\r
145 void LoadLBM (char *filename, byte **picture, byte **palette)
\r
147 byte *LBMbuffer, *picbuffer, *cmapbuffer;
\r
149 byte *LBM_P, *LBMEND_P;
\r
153 int formtype,formlength;
\r
154 int chunktype,chunklength;
\r
156 // qiet compiler warnings
\r
163 LoadFile (filename, (void **)&LBMbuffer);
\r
166 // parse the LBM header
\r
169 if ( *(int *)LBMbuffer != LittleLong(FORMID) )
\r
170 Error ("No FORM ID at start of file!\n");
\r
173 formlength = BigLong( *(int *)LBM_P );
\r
175 LBMEND_P = LBM_P + Align(formlength);
\r
177 formtype = LittleLong(*(int *)LBM_P);
\r
179 if (formtype != ILBMID && formtype != PBMID)
\r
180 Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff
\r
181 ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff);
\r
189 while (LBM_P < LBMEND_P)
\r
191 chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24);
\r
193 chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24);
\r
196 switch ( chunktype )
\r
199 memcpy (&bmhd,LBM_P,sizeof(bmhd));
\r
200 bmhd.w = BigShort(bmhd.w);
\r
201 bmhd.h = BigShort(bmhd.h);
\r
202 bmhd.x = BigShort(bmhd.x);
\r
203 bmhd.y = BigShort(bmhd.y);
\r
204 bmhd.pageWidth = BigShort(bmhd.pageWidth);
\r
205 bmhd.pageHeight = BigShort(bmhd.pageHeight);
\r
209 cmapbuffer = malloc (768);
\r
210 memset (cmapbuffer, 0, 768);
\r
211 memcpy (cmapbuffer, LBM_P, chunklength);
\r
217 pic_p = picbuffer = malloc (bmhd.w*bmhd.h);
\r
218 if (formtype == PBMID)
\r
223 for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
\r
225 if (bmhd.compression == cm_rle1)
\r
226 body_p = LBMRLEDecompress ((byte *)body_p
\r
228 else if (bmhd.compression == cm_none)
\r
230 memcpy (pic_p,body_p,bmhd.w);
\r
231 body_p += Align(bmhd.w);
\r
241 Error ("%s is an interlaced LBM, not packed", filename);
\r
246 LBM_P += Align(chunklength);
\r
251 *picture = picbuffer;
\r
254 *palette = cmapbuffer;
\r
259 ============================================================================
\r
263 ============================================================================
\r
271 void WriteLBMfile (char *filename, byte *data,
\r
272 int width, int height, byte *palette)
\r
274 byte *lbm, *lbmptr;
\r
275 int *formlength, *bmhdlength, *cmaplength, *bodylength;
\r
279 lbm = lbmptr = malloc (width*height+1000);
\r
289 formlength = (int*)lbmptr;
\r
290 lbmptr+=4; // leave space for length
\r
305 bmhdlength = (int *)lbmptr;
\r
306 lbmptr+=4; // leave space for length
\r
308 memset (&basebmhd,0,sizeof(basebmhd));
\r
309 basebmhd.w = BigShort((short)width);
\r
310 basebmhd.h = BigShort((short)height);
\r
311 basebmhd.nPlanes = BigShort(8);
\r
312 basebmhd.xAspect = BigShort(5);
\r
313 basebmhd.yAspect = BigShort(6);
\r
314 basebmhd.pageWidth = BigShort((short)width);
\r
315 basebmhd.pageHeight = BigShort((short)height);
\r
317 memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
\r
318 lbmptr += sizeof(basebmhd);
\r
320 length = lbmptr-(byte *)bmhdlength-4;
\r
321 *bmhdlength = BigLong(length);
\r
323 *lbmptr++ = 0; // pad chunk to even offset
\r
333 cmaplength = (int *)lbmptr;
\r
334 lbmptr+=4; // leave space for length
\r
336 memcpy (lbmptr,palette,768);
\r
339 length = lbmptr-(byte *)cmaplength-4;
\r
340 *cmaplength = BigLong(length);
\r
342 *lbmptr++ = 0; // pad chunk to even offset
\r
352 bodylength = (int *)lbmptr;
\r
353 lbmptr+=4; // leave space for length
\r
355 memcpy (lbmptr,data,width*height);
\r
356 lbmptr += width*height;
\r
358 length = lbmptr-(byte *)bodylength-4;
\r
359 *bodylength = BigLong(length);
\r
361 *lbmptr++ = 0; // pad chunk to even offset
\r
366 length = lbmptr-(byte *)formlength-4;
\r
367 *formlength = BigLong(length);
\r
369 *lbmptr++ = 0; // pad chunk to even offset
\r
372 // write output file
\r
374 SaveFile (filename, lbm, lbmptr-lbm);
\r
380 ============================================================================
\r
384 ============================================================================
\r
392 char bits_per_pixel;
\r
393 unsigned short xmin,ymin,xmax,ymax;
\r
394 unsigned short hres,vres;
\r
395 unsigned char palette[48];
\r
398 unsigned short bytes_per_line;
\r
399 unsigned short palette_type;
\r
401 unsigned char data; // unbounded
\r
410 void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
\r
416 int dataByte, runLength;
\r
422 len = LoadFile (filename, (void **)&raw);
\r
425 // parse the PCX file
\r
427 pcx = (pcx_t *)raw;
\r
430 pcx->xmin = LittleShort(pcx->xmin);
\r
431 pcx->ymin = LittleShort(pcx->ymin);
\r
432 pcx->xmax = LittleShort(pcx->xmax);
\r
433 pcx->ymax = LittleShort(pcx->ymax);
\r
434 pcx->hres = LittleShort(pcx->hres);
\r
435 pcx->vres = LittleShort(pcx->vres);
\r
436 pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
\r
437 pcx->palette_type = LittleShort(pcx->palette_type);
\r
439 if (pcx->manufacturer != 0x0a
\r
440 || pcx->version != 5
\r
441 || pcx->encoding != 1
\r
442 || pcx->bits_per_pixel != 8
\r
443 || pcx->xmax >= 640
\r
444 || pcx->ymax >= 480)
\r
445 Error ("Bad pcx file %s", filename);
\r
449 *palette = malloc(768);
\r
450 memcpy (*palette, (byte *)pcx + len - 768, 768);
\r
454 *width = pcx->xmax+1;
\r
456 *height = pcx->ymax+1;
\r
461 out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
\r
463 Error ("Skin_Cache: couldn't allocate");
\r
469 for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
\r
471 for (x=0 ; x<=pcx->xmax ; )
\r
475 if((dataByte & 0xC0) == 0xC0)
\r
477 runLength = dataByte & 0x3F;
\r
483 while(runLength-- > 0)
\r
484 pix[x++] = dataByte;
\r
489 if ( raw - (byte *)pcx > len)
\r
490 Error ("PCX file %s was malformed", filename);
\r
500 void WritePCXfile (char *filename, byte *data,
\r
501 int width, int height, byte *palette)
\r
507 pcx = malloc (width*height*2+1000);
\r
508 memset (pcx, 0, sizeof(*pcx));
\r
510 pcx->manufacturer = 0x0a; // PCX id
\r
511 pcx->version = 5; // 256 color
\r
512 pcx->encoding = 1; // uncompressed
\r
513 pcx->bits_per_pixel = 8; // 256 color
\r
516 pcx->xmax = LittleShort((short)(width-1));
\r
517 pcx->ymax = LittleShort((short)(height-1));
\r
518 pcx->hres = LittleShort((short)width);
\r
519 pcx->vres = LittleShort((short)height);
\r
520 pcx->color_planes = 1; // chunky image
\r
521 pcx->bytes_per_line = LittleShort((short)width);
\r
522 pcx->palette_type = LittleShort(2); // not a grey scale
\r
527 for (i=0 ; i<height ; i++)
\r
529 for (j=0 ; j<width ; j++)
\r
531 if ( (*data & 0xc0) != 0xc0)
\r
541 // write the palette
\r
542 *pack++ = 0x0c; // palette ID byte
\r
543 for (i=0 ; i<768 ; i++)
\r
544 *pack++ = *palette++;
\r
546 // write output file
\r
547 length = pack - (byte *)pcx;
\r
548 SaveFile (filename, pcx, length);
\r
555 ============================================================================
\r
559 ============================================================================
\r
566 Will load either an lbm or pcx, depending on extension.
\r
567 Any of the return pointers can be NULL if you don't want them.
\r
570 void Load256Image (char *name, byte **pixels, byte **palette,
\r
571 int *width, int *height)
\r
575 ExtractFileExtension (name, ext);
\r
576 if (!Q_strncasecmp (ext, "lbm", strlen(ext) ))
\r
578 LoadLBM (name, pixels, palette);
\r
584 else if (!Q_strncasecmp (ext, "pcx",strlen(ext)))
\r
586 LoadPCX (name, pixels, palette, width, height);
\r
589 Error ("%s doesn't have a known image extension", name);
\r
597 Will save either an lbm or pcx, depending on extension.
\r
600 void Save256Image (char *name, byte *pixels, byte *palette,
\r
601 int width, int height)
\r
605 ExtractFileExtension (name, ext);
\r
606 if (!Q_strncasecmp (ext, "lbm",strlen(ext)))
\r
608 WriteLBMfile (name, pixels, width, height, palette);
\r
610 else if (!Q_strncasecmp (ext, "pcx",strlen(ext)))
\r
612 WritePCXfile (name, pixels, width, height, palette);
\r
615 Error ("%s doesn't have a known image extension", name);
\r
622 ============================================================================
\r
626 ============================================================================
\r
629 typedef struct _TargaHeader {
\r
630 unsigned char id_length, colormap_type, image_type;
\r
631 unsigned short colormap_index, colormap_length;
\r
632 unsigned char colormap_size;
\r
633 unsigned short x_origin, y_origin, width, height;
\r
634 unsigned char pixel_size, attributes;
\r
637 int fgetLittleShort (FILE *f)
\r
644 return (short)(b1 + b2*256);
\r
647 int fgetLittleLong (FILE *f)
\r
649 byte b1, b2, b3, b4;
\r
656 return b1 + (b2<<8) + (b3<<16) + (b4<<24);
\r
665 void LoadTGA (char *name, byte **pixels, int *width, int *height)
\r
667 int columns, rows, numPixels;
\r
672 TargaHeader targa_header;
\r
674 fin = fopen (name, "rb");
\r
676 Error ("Couldn't read %s", name);
\r
678 targa_header.id_length = fgetc(fin);
\r
679 targa_header.colormap_type = fgetc(fin);
\r
680 targa_header.image_type = fgetc(fin);
\r
682 targa_header.colormap_index = fgetLittleShort(fin);
\r
683 targa_header.colormap_length = fgetLittleShort(fin);
\r
684 targa_header.colormap_size = fgetc(fin);
\r
685 targa_header.x_origin = fgetLittleShort(fin);
\r
686 targa_header.y_origin = fgetLittleShort(fin);
\r
687 targa_header.width = fgetLittleShort(fin);
\r
688 targa_header.height = fgetLittleShort(fin);
\r
689 targa_header.pixel_size = fgetc(fin);
\r
690 targa_header.attributes = fgetc(fin);
\r
692 if (targa_header.image_type!=2
\r
693 && targa_header.image_type!=10)
\r
694 Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
\r
696 if (targa_header.colormap_type !=0
\r
697 || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
\r
698 Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
\r
700 columns = targa_header.width;
\r
701 rows = targa_header.height;
\r
702 numPixels = columns * rows;
\r
708 targa_rgba = malloc(numPixels*4);
\r
709 *pixels = targa_rgba;
\r
711 if (targa_header.id_length != 0)
\r
712 fseek(fin, targa_header.id_length, SEEK_CUR); // skip TARGA image comment
\r
714 if (targa_header.image_type==2) { // Uncompressed, RGB images
\r
715 for(row=rows-1; row>=0; row--) {
\r
716 pixbuf = targa_rgba + row*columns*4;
\r
717 for(column=0; column<columns; column++) {
\r
718 unsigned char red,green,blue,alphabyte;
\r
719 switch (targa_header.pixel_size) {
\r
734 alphabyte = getc(fin);
\r
738 *pixbuf++ = alphabyte;
\r
744 else if (targa_header.image_type==10) { // Runlength encoded RGB images
\r
745 unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
\r
746 for(row=rows-1; row>=0; row--) {
\r
747 pixbuf = targa_rgba + row*columns*4;
\r
748 for(column=0; column<columns; ) {
\r
749 packetHeader=getc(fin);
\r
750 packetSize = 1 + (packetHeader & 0x7f);
\r
751 if (packetHeader & 0x80) { // run-length packet
\r
752 switch (targa_header.pixel_size) {
\r
763 alphabyte = getc(fin);
\r
767 for(j=0;j<packetSize;j++) {
\r
771 *pixbuf++=alphabyte;
\r
773 if (column==columns) { // run spans across rows
\r
779 pixbuf = targa_rgba + row*columns*4;
\r
783 else { // non run-length packet
\r
784 for(j=0;j<packetSize;j++) {
\r
785 switch (targa_header.pixel_size) {
\r
799 alphabyte = getc(fin);
\r
803 *pixbuf++ = alphabyte;
\r
807 if (column==columns) { // pixel packet run spans across rows
\r
813 pixbuf = targa_rgba + row*columns*4;
\r
822 // vertically flipped
\r
823 if ( (targa_header.attributes & (1<<5)) ) {
\r
825 for (row = 0; row < .5f * rows; row++)
\r
827 for (column = 0; column < columns; column++)
\r
829 flip = *( (int*)targa_rgba + row * columns + column);
\r
830 *( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column );
\r
831 *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip;
\r