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
30 ============================================================================
34 ============================================================================
38 typedef unsigned char UBYTE;
39 //conflicts with windows typedef short WORD;
40 typedef unsigned short UWORD;
65 UWORD transparentColor;
66 UBYTE xAspect,yAspect;
67 short pageWidth,pageHeight;
70 extern bmhd_t bmhd; // will be in native byte order
74 #define FORMID ( 'F' + ( 'O' << 8 ) + ( (int)'R' << 16 ) + ( (int)'M' << 24 ) )
75 #define ILBMID ( 'I' + ( 'L' << 8 ) + ( (int)'B' << 16 ) + ( (int)'M' << 24 ) )
76 #define PBMID ( 'P' + ( 'B' << 8 ) + ( (int)'M' << 16 ) + ( (int)' ' << 24 ) )
77 #define BMHDID ( 'B' + ( 'M' << 8 ) + ( (int)'H' << 16 ) + ( (int)'D' << 24 ) )
78 #define BODYID ( 'B' + ( 'O' << 8 ) + ( (int)'D' << 16 ) + ( (int)'Y' << 24 ) )
79 #define CMAPID ( 'C' + ( 'M' << 8 ) + ( (int)'A' << 16 ) + ( (int)'P' << 24 ) )
97 Source must be evenly aligned!
100 byte *LBMRLEDecompress( byte *source,byte *unpacked, int bpwidth ){
111 rept = ( rept ^ 0xff ) + 2;
113 memset( unpacked,b,rept );
116 else if ( rept < 0x80 ) {
118 memcpy( unpacked,source,rept );
123 rept = 0; // rept of 0x80 is NOP
128 } while ( count < bpwidth );
130 if ( count > bpwidth ) {
131 Error( "Decompression exceeded width!\n" );
144 void LoadLBM( char *filename, byte **picture, byte **palette ){
145 byte *LBMbuffer, *picbuffer, *cmapbuffer;
147 byte *LBM_P, *LBMEND_P;
151 int formtype,formlength;
152 int chunktype,chunklength;
154 // qiet compiler warnings
161 LoadFile( filename, (void **)&LBMbuffer );
164 // parse the LBM header
167 if ( *(int *)LBMbuffer != LittleLong( FORMID ) ) {
168 Error( "No FORM ID at start of file!\n" );
172 formlength = BigLong( *(int *)LBM_P );
174 LBMEND_P = LBM_P + Align( formlength );
176 formtype = LittleLong( *(int *)LBM_P );
178 if ( formtype != ILBMID && formtype != PBMID ) {
179 Error( "Unrecognized form type: %c%c%c%c\n", formtype & 0xff
180 ,( formtype >> 8 ) & 0xff,( formtype >> 16 ) & 0xff,( formtype >> 24 ) & 0xff );
189 while ( LBM_P < LBMEND_P )
191 chunktype = LBM_P[0] + ( LBM_P[1] << 8 ) + ( LBM_P[2] << 16 ) + ( LBM_P[3] << 24 );
193 chunklength = LBM_P[3] + ( LBM_P[2] << 8 ) + ( LBM_P[1] << 16 ) + ( LBM_P[0] << 24 );
199 memcpy( &bmhd,LBM_P,sizeof( bmhd ) );
200 bmhd.w = BigShort( bmhd.w );
201 bmhd.h = BigShort( bmhd.h );
202 bmhd.x = BigShort( bmhd.x );
203 bmhd.y = BigShort( bmhd.y );
204 bmhd.pageWidth = BigShort( bmhd.pageWidth );
205 bmhd.pageHeight = BigShort( bmhd.pageHeight );
209 cmapbuffer = malloc( 768 );
210 memset( cmapbuffer, 0, 768 );
211 memcpy( cmapbuffer, LBM_P, chunklength );
217 pic_p = picbuffer = malloc( bmhd.w * bmhd.h );
218 if ( formtype == PBMID ) {
222 for ( y = 0 ; y < bmhd.h ; y++, pic_p += bmhd.w )
224 if ( bmhd.compression == cm_rle1 ) {
225 body_p = LBMRLEDecompress( (byte *)body_p
228 else if ( bmhd.compression == cm_none ) {
229 memcpy( pic_p,body_p,bmhd.w );
230 body_p += Align( bmhd.w );
240 Error( "%s is an interlaced LBM, not packed", filename );
245 LBM_P += Align( chunklength );
250 *picture = picbuffer;
253 *palette = cmapbuffer;
259 ============================================================================
263 ============================================================================
271 void WriteLBMfile( char *filename, byte *data,
272 int width, int height, byte *palette ){
274 int *formlength, *bmhdlength, *cmaplength, *bodylength;
278 lbm = lbmptr = malloc( width * height + 1000 );
288 formlength = (int*)lbmptr;
289 lbmptr += 4; // leave space for length
304 bmhdlength = (int *)lbmptr;
305 lbmptr += 4; // leave space for length
307 memset( &basebmhd,0,sizeof( basebmhd ) );
308 basebmhd.w = BigShort( (short)width );
309 basebmhd.h = BigShort( (short)height );
310 basebmhd.nPlanes = BigShort( 8 );
311 basebmhd.xAspect = BigShort( 5 );
312 basebmhd.yAspect = BigShort( 6 );
313 basebmhd.pageWidth = BigShort( (short)width );
314 basebmhd.pageHeight = BigShort( (short)height );
316 memcpy( lbmptr,&basebmhd,sizeof( basebmhd ) );
317 lbmptr += sizeof( basebmhd );
319 length = lbmptr - (byte *)bmhdlength - 4;
320 *bmhdlength = BigLong( length );
322 *lbmptr++ = 0; // pad chunk to even offset
333 cmaplength = (int *)lbmptr;
334 lbmptr += 4; // leave space for length
336 memcpy( lbmptr,palette,768 );
339 length = lbmptr - (byte *)cmaplength - 4;
340 *cmaplength = BigLong( length );
342 *lbmptr++ = 0; // pad chunk to even offset
353 bodylength = (int *)lbmptr;
354 lbmptr += 4; // leave space for length
356 memcpy( lbmptr,data,width * height );
357 lbmptr += width * height;
359 length = lbmptr - (byte *)bodylength - 4;
360 *bodylength = BigLong( length );
362 *lbmptr++ = 0; // pad chunk to even offset
368 length = lbmptr - (byte *)formlength - 4;
369 *formlength = BigLong( length );
371 *lbmptr++ = 0; // pad chunk to even offset
377 SaveFile( filename, lbm, lbmptr - lbm );
383 ============================================================================
387 ============================================================================
396 unsigned short xmin,ymin,xmax,ymax;
397 unsigned short hres,vres;
398 unsigned char palette[48];
401 unsigned short bytes_per_line;
402 unsigned short palette_type;
404 unsigned char data; // unbounded
413 void LoadPCX( char *filename, byte **pic, byte **palette, int *width, int *height ){
418 int dataByte, runLength;
424 len = LoadFile( filename, (void **)&raw );
427 // parse the PCX file
432 pcx->xmin = LittleShort( pcx->xmin );
433 pcx->ymin = LittleShort( pcx->ymin );
434 pcx->xmax = LittleShort( pcx->xmax );
435 pcx->ymax = LittleShort( pcx->ymax );
436 pcx->hres = LittleShort( pcx->hres );
437 pcx->vres = LittleShort( pcx->vres );
438 pcx->bytes_per_line = LittleShort( pcx->bytes_per_line );
439 pcx->palette_type = LittleShort( pcx->palette_type );
441 if ( pcx->manufacturer != 0x0a
443 || pcx->encoding != 1
444 || pcx->bits_per_pixel != 8
446 || pcx->ymax >= 480 ) {
447 Error( "Bad pcx file %s", filename );
451 *palette = malloc( 768 );
452 memcpy( *palette, (byte *)pcx + len - 768, 768 );
456 *width = pcx->xmax + 1;
459 *height = pcx->ymax + 1;
466 out = malloc( ( pcx->ymax + 1 ) * ( pcx->xmax + 1 ) );
468 Error( "Skin_Cache: couldn't allocate" );
475 for ( y = 0 ; y <= pcx->ymax ; y++, pix += pcx->xmax + 1 )
477 for ( x = 0 ; x <= pcx->xmax ; )
481 if ( ( dataByte & 0xC0 ) == 0xC0 ) {
482 runLength = dataByte & 0x3F;
489 while ( runLength-- > 0 )
495 if ( raw - (byte *)pcx > len ) {
496 Error( "PCX file %s was malformed", filename );
507 void WritePCXfile( char *filename, byte *data,
508 int width, int height, byte *palette ){
513 pcx = malloc( width * height * 2 + 1000 );
514 memset( pcx, 0, sizeof( *pcx ) );
516 pcx->manufacturer = 0x0a; // PCX id
517 pcx->version = 5; // 256 color
518 pcx->encoding = 1; // uncompressed
519 pcx->bits_per_pixel = 8; // 256 color
522 pcx->xmax = LittleShort( (short)( width - 1 ) );
523 pcx->ymax = LittleShort( (short)( height - 1 ) );
524 pcx->hres = LittleShort( (short)width );
525 pcx->vres = LittleShort( (short)height );
526 pcx->color_planes = 1; // chunky image
527 pcx->bytes_per_line = LittleShort( (short)width );
528 pcx->palette_type = LittleShort( 2 ); // not a grey scale
533 for ( i = 0 ; i < height ; i++ )
535 for ( j = 0 ; j < width ; j++ )
537 if ( ( *data & 0xc0 ) != 0xc0 ) {
549 *pack++ = 0x0c; // palette ID byte
550 for ( i = 0 ; i < 768 ; i++ )
551 *pack++ = *palette++;
554 length = pack - (byte *)pcx;
555 SaveFile( filename, pcx, length );
562 ============================================================================
566 ============================================================================
573 Will load either an lbm or pcx, depending on extension.
574 Any of the return pointers can be NULL if you don't want them.
577 void Load256Image( char *name, byte **pixels, byte **palette,
578 int *width, int *height ){
581 ExtractFileExtension( name, ext );
582 if ( !Q_strncasecmp( ext, "lbm", strlen( ext ) ) ) {
583 LoadLBM( name, pixels, palette );
591 else if ( !Q_strncasecmp( ext, "pcx",strlen( ext ) ) ) {
592 LoadPCX( name, pixels, palette, width, height );
595 Error( "%s doesn't have a known image extension", name );
604 Will save either an lbm or pcx, depending on extension.
607 void Save256Image( char *name, byte *pixels, byte *palette,
608 int width, int height ){
611 ExtractFileExtension( name, ext );
612 if ( !Q_strncasecmp( ext, "lbm",strlen( ext ) ) ) {
613 WriteLBMfile( name, pixels, width, height, palette );
615 else if ( !Q_strncasecmp( ext, "pcx",strlen( ext ) ) ) {
616 WritePCXfile( name, pixels, width, height, palette );
619 Error( "%s doesn't have a known image extension", name );
627 ============================================================================
631 ============================================================================
634 typedef struct _TargaHeader {
635 unsigned char id_length, colormap_type, image_type;
636 unsigned short colormap_index, colormap_length;
637 unsigned char colormap_size;
638 unsigned short x_origin, y_origin, width, height;
639 unsigned char pixel_size, attributes;
642 int fgetLittleShort( FILE *f ){
648 return (short)( b1 + b2 * 256 );
651 int fgetLittleLong( FILE *f ){
659 return b1 + ( b2 << 8 ) + ( b3 << 16 ) + ( b4 << 24 );
668 void LoadTGA( char *name, byte **pixels, int *width, int *height ){
669 int columns, rows, numPixels;
674 TargaHeader targa_header;
676 fin = fopen( name, "rb" );
678 Error( "Couldn't read %s", name );
681 targa_header.id_length = fgetc( fin );
682 targa_header.colormap_type = fgetc( fin );
683 targa_header.image_type = fgetc( fin );
685 targa_header.colormap_index = fgetLittleShort( fin );
686 targa_header.colormap_length = fgetLittleShort( fin );
687 targa_header.colormap_size = fgetc( fin );
688 targa_header.x_origin = fgetLittleShort( fin );
689 targa_header.y_origin = fgetLittleShort( fin );
690 targa_header.width = fgetLittleShort( fin );
691 targa_header.height = fgetLittleShort( fin );
692 targa_header.pixel_size = fgetc( fin );
693 targa_header.attributes = fgetc( fin );
695 if ( targa_header.image_type != 2
696 && targa_header.image_type != 10 ) {
697 Error( "LoadTGA: Only type 2 and 10 targa RGB images supported\n" );
700 if ( targa_header.colormap_type != 0
701 || ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) ) {
702 Error( "Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n" );
705 columns = targa_header.width;
706 rows = targa_header.height;
707 numPixels = columns * rows;
715 targa_rgba = malloc( numPixels * 4 );
716 *pixels = targa_rgba;
718 if ( targa_header.id_length != 0 ) {
719 fseek( fin, targa_header.id_length, SEEK_CUR ); // skip TARGA image comment
722 if ( targa_header.image_type == 2 ) { // Uncompressed, RGB images
723 for ( row = rows - 1; row >= 0; row-- ) {
724 pixbuf = targa_rgba + row * columns * 4;
725 for ( column = 0; column < columns; column++ ) {
726 unsigned char red,green,blue,alphabyte;
727 switch ( targa_header.pixel_size ) {
742 alphabyte = getc( fin );
746 *pixbuf++ = alphabyte;
752 else if ( targa_header.image_type == 10 ) { // Runlength encoded RGB images
753 unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
754 for ( row = rows - 1; row >= 0; row-- ) {
755 pixbuf = targa_rgba + row * columns * 4;
756 for ( column = 0; column < columns; ) {
757 packetHeader = getc( fin );
758 packetSize = 1 + ( packetHeader & 0x7f );
759 if ( packetHeader & 0x80 ) { // run-length packet
760 switch ( targa_header.pixel_size ) {
771 alphabyte = getc( fin );
775 for ( j = 0; j < packetSize; j++ ) {
779 *pixbuf++ = alphabyte;
781 if ( column == columns ) { // run spans across rows
789 pixbuf = targa_rgba + row * columns * 4;
793 else { // non run-length packet
794 for ( j = 0; j < packetSize; j++ ) {
795 switch ( targa_header.pixel_size ) {
809 alphabyte = getc( fin );
813 *pixbuf++ = alphabyte;
817 if ( column == columns ) { // pixel packet run spans across rows
825 pixbuf = targa_rgba + row * columns * 4;
834 // vertically flipped
835 if ( ( targa_header.attributes & ( 1 << 5 ) ) ) {
837 for ( row = 0; row < .5f * rows; row++ )
839 for ( column = 0; column < columns; column++ )
841 flip = *( (int*)targa_rgba + row * columns + column );
842 *( (int*)targa_rgba + row * columns + column ) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column );
843 *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip;