X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fnetradiant.git;a=blobdiff_plain;f=tools%2Fquake3%2Fcommon%2Fimagelib.c;h=3a5902924879880f863cb0fed11408bfbeb17ccf;hp=5971d8101d69cc34d54f6ed8d67f4cf054d5c2c0;hb=c39d9bef62a4df76d4be0fe34fd51f12adcef364;hpb=12b372f89ce109a4db9d510884fbe7d05af79870 diff --git a/tools/quake3/common/imagelib.c b/tools/quake3/common/imagelib.c index 5971d810..3a590292 100644 --- a/tools/quake3/common/imagelib.c +++ b/tools/quake3/common/imagelib.c @@ -1,95 +1,94 @@ /* -Copyright (C) 1999-2006 Id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. + Copyright (C) 1999-2006 Id Software, Inc. and contributors. + For a list of contributors, see the accompanying CONTRIBUTORS file. -This file is part of GtkRadiant. + This file is part of GtkRadiant. -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + GtkRadiant is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + GtkRadiant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + You should have received a copy of the GNU General Public License + along with GtkRadiant; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ // imagelib.c #include "inout.h" #include "cmdlib.h" +#include "etclib.h" #include "imagelib.h" #include "vfs.h" -int fgetLittleShort (FILE *f) -{ - byte b1, b2; +int fgetLittleShort( FILE *f ){ + byte b1, b2; - b1 = fgetc(f); - b2 = fgetc(f); + b1 = fgetc( f ); + b2 = fgetc( f ); - return (short)(b1 + b2*256); + return (short)( b1 + b2 * 256 ); } -int fgetLittleLong (FILE *f) -{ - byte b1, b2, b3, b4; +int fgetLittleLong( FILE *f ){ + byte b1, b2, b3, b4; - b1 = fgetc(f); - b2 = fgetc(f); - b3 = fgetc(f); - b4 = fgetc(f); + b1 = fgetc( f ); + b2 = fgetc( f ); + b3 = fgetc( f ); + b4 = fgetc( f ); - return b1 + (b2<<8) + (b3<<16) + (b4<<24); + return b1 + ( b2 << 8 ) + ( b3 << 16 ) + ( b4 << 24 ); } -int bufLittleShort (byte *buf, int len, int *pos) -{ - byte b1, b2; +int bufLittleShort( byte *buf, int len, int *pos ){ + byte b1, b2; - if ((len - *pos) < 2) - Error ("Unexpected buffer end"); + if ( ( len - *pos ) < 2 ) { + Error( "Unexpected buffer end" ); + } - b1 = buf[*pos]; *pos += 1; - b2 = buf[*pos]; *pos += 1; + b1 = buf[*pos]; *pos += 1; + b2 = buf[*pos]; *pos += 1; - return (short)(b1 + b2*256); + return (short)( b1 + b2 * 256 ); } -int bufLittleLong (byte *buf, int len, int *pos) -{ - byte b1, b2, b3, b4; +int bufLittleLong( byte *buf, int len, int *pos ){ + byte b1, b2, b3, b4; - if ((len - *pos) < 4) - Error ("Unexpected buffer end"); + if ( ( len - *pos ) < 4 ) { + Error( "Unexpected buffer end" ); + } - b1 = buf[*pos]; *pos += 1; - b2 = buf[*pos]; *pos += 1; - b3 = buf[*pos]; *pos += 1; - b4 = buf[*pos]; *pos += 1; + b1 = buf[*pos]; *pos += 1; + b2 = buf[*pos]; *pos += 1; + b3 = buf[*pos]; *pos += 1; + b4 = buf[*pos]; *pos += 1; - return b1 + (b2<<8) + (b3<<16) + (b4<<24); + return b1 + ( b2 << 8 ) + ( b3 << 16 ) + ( b4 << 24 ); } /* -============================================================================ + ============================================================================ - LBM STUFF + LBM STUFF -============================================================================ -*/ + ============================================================================ + */ -typedef unsigned char UBYTE; +typedef unsigned char UBYTE; //conflicts with windows typedef short WORD; -typedef unsigned short UWORD; -typedef long LONG; +typedef unsigned short UWORD; +typedef long LONG; typedef enum { @@ -107,51 +106,50 @@ typedef enum typedef struct { - UWORD w,h; - short x,y; - UBYTE nPlanes; - UBYTE masking; - UBYTE compression; - UBYTE pad1; - UWORD transparentColor; - UBYTE xAspect,yAspect; - short pageWidth,pageHeight; + UWORD w,h; + short x,y; + UBYTE nPlanes; + UBYTE masking; + UBYTE compression; + UBYTE pad1; + UWORD transparentColor; + UBYTE xAspect,yAspect; + short pageWidth,pageHeight; } bmhd_t; -extern bmhd_t bmhd; // will be in native byte order +extern bmhd_t bmhd; // will be in native byte order -#define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24)) -#define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24)) -#define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24)) -#define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24)) -#define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24)) -#define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24)) +#define FORMID ( 'F' + ( 'O' << 8 ) + ( (int)'R' << 16 ) + ( (int)'M' << 24 ) ) +#define ILBMID ( 'I' + ( 'L' << 8 ) + ( (int)'B' << 16 ) + ( (int)'M' << 24 ) ) +#define PBMID ( 'P' + ( 'B' << 8 ) + ( (int)'M' << 16 ) + ( (int)' ' << 24 ) ) +#define BMHDID ( 'B' + ( 'M' << 8 ) + ( (int)'H' << 16 ) + ( (int)'D' << 24 ) ) +#define BODYID ( 'B' + ( 'O' << 8 ) + ( (int)'D' << 16 ) + ( (int)'Y' << 24 ) ) +#define CMAPID ( 'C' + ( 'M' << 8 ) + ( (int)'A' << 16 ) + ( (int)'P' << 24 ) ) -bmhd_t bmhd; +bmhd_t bmhd; -int Align (int l) -{ - if (l&1) - return l+1; +int Align( int l ){ + if ( l & 1 ) { + return l + 1; + } return l; } /* -================ -LBMRLEdecompress + ================ + LBMRLEdecompress -Source must be evenly aligned! -================ -*/ -byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth) -{ - int count; - byte b,rept; + Source must be evenly aligned! + ================ + */ +byte *LBMRLEDecompress( byte *source,byte *unpacked, int bpwidth ){ + int count; + byte b,rept; count = 0; @@ -159,29 +157,29 @@ byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth) { rept = *source++; - if (rept > 0x80) - { - rept = (rept^0xff)+2; + if ( rept > 0x80 ) { + rept = ( rept ^ 0xff ) + 2; b = *source++; - memset(unpacked,b,rept); + memset( unpacked,b,rept ); unpacked += rept; } - else if (rept < 0x80) - { + else if ( rept < 0x80 ) { rept++; - memcpy(unpacked,source,rept); + memcpy( unpacked,source,rept ); unpacked += rept; source += rept; } - else + else{ rept = 0; // rept of 0x80 is NOP + } count += rept; - } while (countbpwidth) - Error ("Decompression exceeded width!\n"); + if ( count > bpwidth ) { + Error( "Decompression exceeded width!\n" ); + } return source; @@ -189,20 +187,19 @@ byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth) /* -================= -LoadLBM -================= -*/ -void LoadLBM (const char *filename, byte **picture, byte **palette) -{ + ================= + LoadLBM + ================= + */ +void LoadLBM( const char *filename, byte **picture, byte **palette ){ byte *LBMbuffer, *picbuffer, *cmapbuffer; - int y; + int y; byte *LBM_P, *LBMEND_P; byte *pic_p; byte *body_p; - int formtype,formlength; - int chunktype,chunklength; + int formtype,formlength; + int chunktype,chunklength; // qiet compiler warnings picbuffer = NULL; @@ -211,25 +208,27 @@ void LoadLBM (const char *filename, byte **picture, byte **palette) // // load the LBM // - LoadFile (filename, (void **)&LBMbuffer); + LoadFile( filename, (void **)&LBMbuffer ); // // parse the LBM header // LBM_P = LBMbuffer; - if ( *(int *)LBMbuffer != LittleLong(FORMID) ) - Error ("No FORM ID at start of file!\n"); + if ( *(int *)LBMbuffer != LittleLong( FORMID ) ) { + Error( "No FORM ID at start of file!\n" ); + } LBM_P += 4; formlength = BigLong( *(int *)LBM_P ); LBM_P += 4; - LBMEND_P = LBM_P + Align(formlength); + LBMEND_P = LBM_P + Align( formlength ); - formtype = LittleLong(*(int *)LBM_P); + formtype = LittleLong( *(int *)LBM_P ); - if (formtype != ILBMID && formtype != PBMID) - Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff - ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff); + if ( formtype != ILBMID && formtype != PBMID ) { + Error( "Unrecognized form type: %c%c%c%c\n", formtype & 0xff + ,( formtype >> 8 ) & 0xff,( formtype >> 16 ) & 0xff,( formtype >> 24 ) & 0xff ); + } LBM_P += 4; @@ -237,97 +236,96 @@ void LoadLBM (const char *filename, byte **picture, byte **palette) // parse chunks // - while (LBM_P < LBMEND_P) + while ( LBM_P < LBMEND_P ) { - chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24); + chunktype = LBM_P[0] + ( LBM_P[1] << 8 ) + ( LBM_P[2] << 16 ) + ( LBM_P[3] << 24 ); LBM_P += 4; - chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24); + chunklength = LBM_P[3] + ( LBM_P[2] << 8 ) + ( LBM_P[1] << 16 ) + ( LBM_P[0] << 24 ); LBM_P += 4; switch ( chunktype ) { case BMHDID: - memcpy (&bmhd,LBM_P,sizeof(bmhd)); - bmhd.w = BigShort(bmhd.w); - bmhd.h = BigShort(bmhd.h); - bmhd.x = BigShort(bmhd.x); - bmhd.y = BigShort(bmhd.y); - bmhd.pageWidth = BigShort(bmhd.pageWidth); - bmhd.pageHeight = BigShort(bmhd.pageHeight); + memcpy( &bmhd,LBM_P,sizeof( bmhd ) ); + bmhd.w = BigShort( bmhd.w ); + bmhd.h = BigShort( bmhd.h ); + bmhd.x = BigShort( bmhd.x ); + bmhd.y = BigShort( bmhd.y ); + bmhd.pageWidth = BigShort( bmhd.pageWidth ); + bmhd.pageHeight = BigShort( bmhd.pageHeight ); break; case CMAPID: - cmapbuffer = safe_malloc (768); - memset (cmapbuffer, 0, 768); - memcpy (cmapbuffer, LBM_P, chunklength); + cmapbuffer = safe_malloc( 768 ); + memset( cmapbuffer, 0, 768 ); + memcpy( cmapbuffer, LBM_P, chunklength ); break; case BODYID: body_p = LBM_P; - pic_p = picbuffer = safe_malloc (bmhd.w*bmhd.h); - if (formtype == PBMID) - { - // - // unpack PBM - // - for (y=0 ; ydata; - pcx->xmin = LittleShort(pcx->xmin); - pcx->ymin = LittleShort(pcx->ymin); - pcx->xmax = LittleShort(pcx->xmax); - pcx->ymax = LittleShort(pcx->ymax); - pcx->hres = LittleShort(pcx->hres); - pcx->vres = LittleShort(pcx->vres); - pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); - pcx->palette_type = LittleShort(pcx->palette_type); - - if (pcx->manufacturer != 0x0a - || pcx->version != 5 - || pcx->encoding != 1 - || pcx->bits_per_pixel != 8 - || pcx->xmax >= 640 - || pcx->ymax >= 480) - Error ("Bad pcx file %s", filename); - - if (palette) - { - *palette = safe_malloc(768); - memcpy (*palette, (byte *)pcx + len - 768, 768); + pcx->xmin = LittleShort( pcx->xmin ); + pcx->ymin = LittleShort( pcx->ymin ); + pcx->xmax = LittleShort( pcx->xmax ); + pcx->ymax = LittleShort( pcx->ymax ); + pcx->hres = LittleShort( pcx->hres ); + pcx->vres = LittleShort( pcx->vres ); + pcx->bytes_per_line = LittleShort( pcx->bytes_per_line ); + pcx->palette_type = LittleShort( pcx->palette_type ); + + if ( pcx->manufacturer != 0x0a + || pcx->version != 5 + || pcx->encoding != 1 + || pcx->bits_per_pixel != 8 + || pcx->xmax >= 640 + || pcx->ymax >= 480 ) { + Error( "Bad pcx file %s", filename ); + } + + if ( palette ) { + *palette = safe_malloc( 768 ); + memcpy( *palette, (byte *)pcx + len - 768, 768 ); } - if (width) - *width = pcx->xmax+1; - if (height) - *height = pcx->ymax+1; + if ( width ) { + *width = pcx->xmax + 1; + } + if ( height ) { + *height = pcx->ymax + 1; + } - if (!pic) + if ( !pic ) { return; + } - out = safe_malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); - if (!out) - Error( "LoadPCX: couldn't allocate"); + out = safe_malloc( ( pcx->ymax + 1 ) * ( pcx->xmax + 1 ) ); + if ( !out ) { + Error( "LoadPCX: couldn't allocate" ); + } *pic = out; pix = out; - + /* RR2DO2: pcx fix */ lsize = pcx->color_planes * pcx->bytes_per_line; - + /* go scanline by scanline */ - for( y = 0; y <= pcx->ymax; y++, pix += pcx->xmax + 1 ) + for ( y = 0; y <= pcx->ymax; y++, pix += pcx->xmax + 1 ) { /* do a scanline */ - for( x=0; x <= pcx->xmax; ) + runLength = 0; + for ( x = 0; x <= pcx->xmax; ) { /* RR2DO2 */ DECODEPCX( raw, dataByte, runLength ); - while( runLength-- > 0 ) + while ( runLength-- > 0 ) pix[ x++ ] = dataByte; } /* RR2DO2: discard any other data */ - while( x < lsize ) + while ( x < lsize ) { DECODEPCX( raw, dataByte, runLength ); x++; } - while( runLength-- > 0 ) + while ( runLength-- > 0 ) x++; } - + /* validity check */ - if( raw - (byte *) pcx > len) + if ( raw - (byte *) pcx > len ) { Error( "PCX file %s was malformed", filename ); + } free( pcx ); } -/* -============== -WritePCXfile -============== -*/ -void WritePCXfile (const char *filename, byte *data, - int width, int height, byte *palette) -{ - int i, j, length; - pcx_t *pcx; - byte *pack; - - pcx = safe_malloc (width*height*2+1000); - memset (pcx, 0, sizeof(*pcx)); - - pcx->manufacturer = 0x0a; // PCX id - pcx->version = 5; // 256 color - pcx->encoding = 1; // uncompressed - pcx->bits_per_pixel = 8; // 256 color +/* + ============== + WritePCXfile + ============== + */ +void WritePCXfile( const char *filename, byte *data, + int width, int height, byte *palette ){ + int i, j, length; + pcx_t *pcx; + byte *pack; + + pcx = safe_malloc( width * height * 2 + 1000 ); + memset( pcx, 0, sizeof( *pcx ) ); + + pcx->manufacturer = 0x0a; // PCX id + pcx->version = 5; // 256 color + pcx->encoding = 1; // uncompressed + pcx->bits_per_pixel = 8; // 256 color pcx->xmin = 0; pcx->ymin = 0; - pcx->xmax = LittleShort((short)(width-1)); - pcx->ymax = LittleShort((short)(height-1)); - pcx->hres = LittleShort((short)width); - pcx->vres = LittleShort((short)height); - pcx->color_planes = 1; // chunky image - pcx->bytes_per_line = LittleShort((short)width); - pcx->palette_type = LittleShort(1); // not a grey scale + pcx->xmax = LittleShort( (short)( width - 1 ) ); + pcx->ymax = LittleShort( (short)( height - 1 ) ); + pcx->hres = LittleShort( (short)width ); + pcx->vres = LittleShort( (short)height ); + pcx->color_planes = 1; // chunky image + pcx->bytes_per_line = LittleShort( (short)width ); + pcx->palette_type = LittleShort( 1 ); // not a grey scale // pack the image pack = &pcx->data; - - for (i=0 ; iid_length, t->colormap_type, t->image_type, t->colormap_index, t->colormap_length, t->colormap_size, t->x_origin, t->y_origin, t->width, t->height, t->pixel_size, t->attributes); +void TargaError( TargaHeader *t, const char *message ){ + Sys_Printf( "%s\n:TargaHeader:\nuint8 id_length = %i;\nuint8 colormap_type = %i;\nuint8 image_type = %i;\nuint16 colormap_index = %i;\nuint16 colormap_length = %i;\nuint8 colormap_size = %i;\nuint16 x_origin = %i;\nuint16 y_origin = %i;\nuint16 width = %i;\nuint16 height = %i;\nuint8 pixel_size = %i;\nuint8 attributes = %i;\n", message, t->id_length, t->colormap_type, t->image_type, t->colormap_index, t->colormap_length, t->colormap_size, t->x_origin, t->y_origin, t->width, t->height, t->pixel_size, t->attributes ); } /* -============= -LoadTGABuffer -============= -*/ -void LoadTGABuffer (const byte *f, const byte *enddata, byte **pic, int *width, int *height) -{ + ============= + LoadTGABuffer + ============= + */ +void LoadTGABuffer( const byte *f, const byte *enddata, byte **pic, int *width, int *height ){ int x, y, row_inc, compressed, readpixelcount, red, green, blue, alpha, runlen, pindex, alphabits, image_width, image_height; byte *pixbuf, *image_rgba; const byte *fin; unsigned char *p; TargaHeader targa_header; - unsigned char palette[256*4]; + unsigned char palette[256 * 4]; *pic = NULL; // abort if it is too small to parse - if (enddata - f < 19) + if ( enddata - f < 19 ) { return; + } targa_header.id_length = f[0]; targa_header.colormap_type = f[1]; @@ -934,102 +936,87 @@ void LoadTGABuffer (const byte *f, const byte *enddata, byte **pic, int *width, // read/skip the colormap if present (note: according to the TARGA spec it // can be present even on truecolor or greyscale images, just not used by // the image data) - if (targa_header.colormap_type) - { - if (targa_header.colormap_length > 256) - { - TargaError(&targa_header, "LoadTGA: only up to 256 colormap_length supported\n"); + if ( targa_header.colormap_type ) { + if ( targa_header.colormap_length > 256 ) { + TargaError( &targa_header, "LoadTGA: only up to 256 colormap_length supported\n" ); return; } - if (targa_header.colormap_index) - { - TargaError(&targa_header, "LoadTGA: colormap_index not supported\n"); + if ( targa_header.colormap_index ) { + TargaError( &targa_header, "LoadTGA: colormap_index not supported\n" ); return; } - if (targa_header.colormap_size == 24) - { - for (x = 0;x < targa_header.colormap_length;x++) + if ( targa_header.colormap_size == 24 ) { + for ( x = 0; x < targa_header.colormap_length; x++ ) { - palette[x*4+2] = *fin++; - palette[x*4+1] = *fin++; - palette[x*4+0] = *fin++; - palette[x*4+3] = 255; + palette[x * 4 + 2] = *fin++; + palette[x * 4 + 1] = *fin++; + palette[x * 4 + 0] = *fin++; + palette[x * 4 + 3] = 255; } } - else if (targa_header.colormap_size == 32) - { - for (x = 0;x < targa_header.colormap_length;x++) + else if ( targa_header.colormap_size == 32 ) { + for ( x = 0; x < targa_header.colormap_length; x++ ) { - palette[x*4+2] = *fin++; - palette[x*4+1] = *fin++; - palette[x*4+0] = *fin++; - palette[x*4+3] = *fin++; + palette[x * 4 + 2] = *fin++; + palette[x * 4 + 1] = *fin++; + palette[x * 4 + 0] = *fin++; + palette[x * 4 + 3] = *fin++; } } else { - TargaError(&targa_header, "LoadTGA: Only 32 and 24 bit colormap_size supported\n"); + TargaError( &targa_header, "LoadTGA: Only 32 and 24 bit colormap_size supported\n" ); return; } } // check our pixel_size restrictions according to image_type - if (targa_header.image_type == 2 || targa_header.image_type == 10) - { - if (targa_header.pixel_size != 24 && targa_header.pixel_size != 32) - { - TargaError(&targa_header, "LoadTGA: only 24bit and 32bit pixel sizes supported for type 2 and type 10 images\n"); + if ( targa_header.image_type == 2 || targa_header.image_type == 10 ) { + if ( targa_header.pixel_size != 24 && targa_header.pixel_size != 32 ) { + TargaError( &targa_header, "LoadTGA: only 24bit and 32bit pixel sizes supported for type 2 and type 10 images\n" ); return; } } - else if (targa_header.image_type == 1 || targa_header.image_type == 9) - { - if (targa_header.pixel_size != 8) - { - TargaError(&targa_header, "LoadTGA: only 8bit pixel size for type 1, 3, 9, and 11 images supported\n"); + else if ( targa_header.image_type == 1 || targa_header.image_type == 9 ) { + if ( targa_header.pixel_size != 8 ) { + TargaError( &targa_header, "LoadTGA: only 8bit pixel size for type 1, 3, 9, and 11 images supported\n" ); return; } } - else if (targa_header.image_type == 3 || targa_header.image_type == 11) - { - if (targa_header.pixel_size != 8) - { - TargaError(&targa_header, "LoadTGA: only 8bit pixel size for type 1, 3, 9, and 11 images supported\n"); + else if ( targa_header.image_type == 3 || targa_header.image_type == 11 ) { + if ( targa_header.pixel_size != 8 ) { + TargaError( &targa_header, "LoadTGA: only 8bit pixel size for type 1, 3, 9, and 11 images supported\n" ); return; } } else { - TargaError(&targa_header, "LoadTGA: Only type 1, 2, 3, 9, 10, and 11 targa RGB images supported"); + TargaError( &targa_header, "LoadTGA: Only type 1, 2, 3, 9, 10, and 11 targa RGB images supported" ); return; } - if (targa_header.attributes & 0x10) - { - TargaError(&targa_header, "LoadTGA: origin must be in top left or bottom left, top right and bottom right are not supported\n"); + if ( targa_header.attributes & 0x10 ) { + TargaError( &targa_header, "LoadTGA: origin must be in top left or bottom left, top right and bottom right are not supported\n" ); return; } // number of attribute bits per pixel, we only support 0 or 8 alphabits = targa_header.attributes & 0x0F; - if (alphabits != 8 && alphabits != 0) - { - TargaError(&targa_header, "LoadTGA: only 0 or 8 attribute (alpha) bits supported\n"); + if ( alphabits != 8 && alphabits != 0 ) { + TargaError( &targa_header, "LoadTGA: only 0 or 8 attribute (alpha) bits supported\n" ); return; } - image_rgba = safe_malloc(image_width * image_height * 4); - if (!image_rgba) - { - Sys_Printf("LoadTGA: not enough memory for %i by %i image\n", image_width, image_height); + image_rgba = safe_malloc( image_width * image_height * 4 ); + if ( !image_rgba ) { + Sys_Printf( "LoadTGA: not enough memory for %i by %i image\n", image_width, image_height ); return; } // If bit 5 of attributes isn't set, the image has been stored from bottom to top - if ((targa_header.attributes & 0x20) == 0) - { - pixbuf = image_rgba + (image_height - 1)*image_width*4; - row_inc = -image_width*4*2; + if ( ( targa_header.attributes & 0x20 ) == 0 ) { + pixbuf = image_rgba + ( image_height - 1 ) * image_width * 4; + row_inc = -image_width * 4 * 2; } else { @@ -1041,36 +1028,35 @@ void LoadTGABuffer (const byte *f, const byte *enddata, byte **pic, int *width, x = 0; y = 0; red = green = blue = alpha = 255; - while (y < image_height) + while ( y < image_height ) { // decoder is mostly the same whether it's compressed or not readpixelcount = 1000000; runlen = 1000000; - if (compressed && fin < enddata) - { + if ( compressed && fin < enddata ) { runlen = *fin++; // high bit indicates this is an RLE compressed run - if (runlen & 0x80) + if ( runlen & 0x80 ) { readpixelcount = 1; - runlen = 1 + (runlen & 0x7f); + } + runlen = 1 + ( runlen & 0x7f ); } - while((runlen--) && y < image_height) + while ( ( runlen-- ) && y < image_height ) { - if (readpixelcount > 0) - { + if ( readpixelcount > 0 ) { readpixelcount--; red = green = blue = alpha = 255; - if (fin < enddata) - { - switch(targa_header.image_type) + if ( fin < enddata ) { + switch ( targa_header.image_type ) { case 1: case 9: // colormapped pindex = *fin++; - if (pindex >= targa_header.colormap_length) + if ( pindex >= targa_header.colormap_length ) { pindex = 0; // error + } p = palette + pindex * 4; red = p[0]; green = p[1]; @@ -1081,12 +1067,15 @@ void LoadTGABuffer (const byte *f, const byte *enddata, byte **pic, int *width, case 10: // BGR or BGRA blue = *fin++; - if (fin < enddata) + if ( fin < enddata ) { green = *fin++; - if (fin < enddata) + } + if ( fin < enddata ) { red = *fin++; - if (targa_header.pixel_size == 32 && fin < enddata) + } + if ( targa_header.pixel_size == 32 && fin < enddata ) { alpha = *fin++; + } break; case 3: case 11: @@ -1094,8 +1083,9 @@ void LoadTGABuffer (const byte *f, const byte *enddata, byte **pic, int *width, red = green = blue = *fin++; break; } - if (!alphabits) + if ( !alphabits ) { alpha = 255; + } } } *pixbuf++ = red; @@ -1103,8 +1093,7 @@ void LoadTGABuffer (const byte *f, const byte *enddata, byte **pic, int *width, *pixbuf++ = blue; *pixbuf++ = alpha; x++; - if (x == image_width) - { + if ( x == image_width ) { // end of line, advance to next x = 0; y++; @@ -1114,117 +1103,432 @@ void LoadTGABuffer (const byte *f, const byte *enddata, byte **pic, int *width, } *pic = image_rgba; - if (width) + if ( width ) { *width = image_width; - if (height) + } + if ( height ) { *height = image_height; + } } /* -============= -LoadTGA -============= -*/ -void LoadTGA (const char *name, byte **pixels, int *width, int *height) -{ - byte *buffer; + ============= + LoadTGA + ============= + */ +void LoadTGA( const char *name, byte **pixels, int *width, int *height ){ + byte *buffer; int nLen; // // load the file // - nLen = vfsLoadFile ( ( char * ) name, (void **)&buffer, 0); - if (nLen == -1) - { - Error ("Couldn't read %s", name); + nLen = vfsLoadFile( name, (void **)&buffer, 0 ); + if ( nLen == -1 ) { + Error( "Couldn't read %s", name ); } - LoadTGABuffer(buffer, buffer + nLen, pixels, width, height); + LoadTGABuffer( buffer, buffer + nLen, pixels, width, height ); } /* -================ -WriteTGA -================ -*/ -void WriteTGA (const char *filename, byte *data, int width, int height) { - byte *buffer; - int i; - int c; - FILE *f; - - buffer = safe_malloc(width*height*4 + 18); - memset (buffer, 0, 18); - buffer[2] = 2; // uncompressed type - buffer[12] = width&255; - buffer[13] = width>>8; - buffer[14] = height&255; - buffer[15] = height>>8; - buffer[16] = 32; // pixel size + ================ + WriteTGA + ================ + */ +void WriteTGA( const char *filename, byte *data, int width, int height ) { + byte *buffer; + int i; + int c; + FILE *f; + + buffer = safe_malloc( width * height * 4 + 18 ); + memset( buffer, 0, 18 ); + buffer[2] = 2; // uncompressed type + buffer[12] = width & 255; + buffer[13] = width >> 8; + buffer[14] = height & 255; + buffer[15] = height >> 8; + buffer[16] = 32; // pixel size // swap rgb to bgr c = 18 + width * height * 4; - for (i=18 ; i> 8; + buffer[14] = height & 255; + buffer[15] = height >> 8; + buffer[16] = 8; // pixel size + + f = fopen( filename, "wb" ); + fwrite( buffer, 1, 18, f ); + fwrite( data, 1, width * height, f ); + fclose( f ); } /* -============================================================================ + ============================================================================ -LOAD32BITIMAGE + LOAD32BITIMAGE -============================================================================ -*/ + ============================================================================ + */ /* -============== -Load32BitImage - -Any of the return pointers can be NULL if you don't want them. -============== -*/ -void Load32BitImage (const char *name, unsigned **pixels, int *width, int *height) -{ - char ext[128]; - byte *palette; - byte *pixels8; - byte *pixels32; - int size; - int i; - int v; - - ExtractFileExtension (name, ext); - if (!Q_stricmp (ext, "tga")) { - LoadTGA (name, (byte **)pixels, width, height); - } else { - Load256Image (name, &pixels8, &palette, width, height); - if (!pixels) { + ============== + Load32BitImage + + Any of the return pointers can be NULL if you don't want them. + ============== + */ +void Load32BitImage( const char *name, unsigned **pixels, int *width, int *height ){ + char ext[128]; + byte *palette; + byte *pixels8; + byte *pixels32; + int size; + int i; + int v; + + ExtractFileExtension( name, ext ); + if ( !Q_stricmp( ext, "tga" ) ) { + LoadTGA( name, (byte **)pixels, width, height ); + } + else { + Load256Image( name, &pixels8, &palette, width, height ); + if ( !pixels ) { return; } size = *width * *height; - pixels32 = safe_malloc(size * 4); + pixels32 = safe_malloc( size * 4 ); *pixels = (unsigned *)pixels32; - for (i = 0 ; i < size ; i++) { + for ( i = 0 ; i < size ; i++ ) { v = pixels8[i]; - pixels32[i*4 + 0] = palette[ v * 3 + 0 ]; - pixels32[i*4 + 1] = palette[ v * 3 + 1 ]; - pixels32[i*4 + 2] = palette[ v * 3 + 2 ]; - pixels32[i*4 + 3] = 0xff; + pixels32[i * 4 + 0] = palette[ v * 3 + 0 ]; + pixels32[i * 4 + 1] = palette[ v * 3 + 1 ]; + pixels32[i * 4 + 2] = palette[ v * 3 + 2 ]; + pixels32[i * 4 + 3] = 0xff; + } + } +} + + +/* + ============================================================================ + + KHRONOS TEXTURE + + ============================================================================ + */ + + +#define KTX_UINT32_LE( buf ) ( ( unsigned int )( (buf)[0] | ( (buf)[1] << 8 ) | ( (buf)[2] << 16 ) | ( (buf)[3] << 24 ) ) ) +#define KTX_UINT32_BE( buf ) ( ( unsigned int )( (buf)[3] | ( (buf)[2] << 8 ) | ( (buf)[1] << 16 ) | ( (buf)[0] << 24 ) ) ) + +#define KTX_TYPE_UNSIGNED_BYTE 0x1401 +#define KTX_TYPE_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define KTX_TYPE_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define KTX_TYPE_UNSIGNED_SHORT_5_6_5 0x8363 + +#define KTX_FORMAT_ALPHA 0x1906 +#define KTX_FORMAT_RGB 0x1907 +#define KTX_FORMAT_RGBA 0x1908 +#define KTX_FORMAT_LUMINANCE 0x1909 +#define KTX_FORMAT_LUMINANCE_ALPHA 0x190A +#define KTX_FORMAT_BGR 0x80E0 +#define KTX_FORMAT_BGRA 0x80E1 + +#define KTX_FORMAT_ETC1_RGB8 0x8D64 + +static void KTX_DecodeA8( const byte *in, qboolean bigEndian, byte *out ){ + out[0] = out[1] = out[2] = 0; + out[3] = in[0]; +} + +static void KTX_DecodeRGB8( const byte *in, qboolean bigEndian, byte *out ){ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = 255; +} + +static void KTX_DecodeRGBA8( const byte *in, qboolean bigEndian, byte *out ){ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; +} + +static void KTX_DecodeL8( const byte *in, qboolean bigEndian, byte *out ){ + out[0] = out[1] = out[2] = in[0]; + out[3] = 255; +} + +static void KTX_DecodeLA8( const byte *in, qboolean bigEndian, byte *out ){ + out[0] = out[1] = out[2] = in[0]; + out[3] = in[1]; +} + +static void KTX_DecodeBGR8( const byte *in, qboolean bigEndian, byte *out ){ + out[0] = in[2]; + out[1] = in[1]; + out[2] = in[0]; + out[3] = 255; +} + +static void KTX_DecodeBGRA8( const byte *in, qboolean bigEndian, byte *out ){ + out[0] = in[2]; + out[1] = in[1]; + out[2] = in[0]; + out[3] = in[3]; +} + +static void KTX_DecodeRGBA4( const byte *in, qboolean bigEndian, byte *out ){ + unsigned short rgba; + int r, g, b, a; + + if ( bigEndian ) { + rgba = ( in[0] << 8 ) | in[1]; + } + else { + rgba = ( in[1] << 8 ) | in[0]; + } + + r = ( rgba >> 12 ) & 0xf; + g = ( rgba >> 8 ) & 0xf; + b = ( rgba >> 4 ) & 0xf; + a = rgba & 0xf; + out[0] = ( r << 4 ) | r; + out[1] = ( g << 4 ) | g; + out[2] = ( b << 4 ) | b; + out[3] = ( a << 4 ) | a; +} + +static void KTX_DecodeRGBA5( const byte *in, qboolean bigEndian, byte *out ){ + unsigned short rgba; + int r, g, b; + + if ( bigEndian ) { + rgba = ( in[0] << 8 ) | in[1]; + } + else { + rgba = ( in[1] << 8 ) | in[0]; + } + + r = ( rgba >> 11 ) & 0x1f; + g = ( rgba >> 6 ) & 0x1f; + b = ( rgba >> 1 ) & 0x1f; + out[0] = ( r << 3 ) | ( r >> 2 ); + out[1] = ( g << 3 ) | ( g >> 2 ); + out[2] = ( b << 3 ) | ( b >> 2 ); + out[3] = ( rgba & 1 ) * 255; +} + +static void KTX_DecodeRGB5( const byte *in, qboolean bigEndian, byte *out ){ + unsigned short rgba; + int r, g, b; + + if ( bigEndian ) { + rgba = ( in[0] << 8 ) | in[1]; + } + else { + rgba = ( in[1] << 8 ) | in[0]; + } + + r = ( rgba >> 11 ) & 0x1f; + g = ( rgba >> 5 ) & 0x3f; + b = rgba & 0x1f; + out[0] = ( r << 3 ) | ( r >> 2 ); + out[1] = ( g << 2 ) | ( g >> 4 ); + out[2] = ( b << 3 ) | ( b >> 2 ); + out[3] = 255; +} + +typedef struct +{ + unsigned int type; + unsigned int format; + unsigned int pixelSize; + void ( *decode )( const byte *in, qboolean bigEndian, byte *out ); +} KTX_UncompressedFormat_t; + +static const KTX_UncompressedFormat_t KTX_UncompressedFormats[] = +{ + { KTX_TYPE_UNSIGNED_BYTE, KTX_FORMAT_ALPHA, 1, KTX_DecodeA8 }, + { KTX_TYPE_UNSIGNED_BYTE, KTX_FORMAT_RGB, 3, KTX_DecodeRGB8 }, + { KTX_TYPE_UNSIGNED_BYTE, KTX_FORMAT_RGBA, 4, KTX_DecodeRGBA8 }, + { KTX_TYPE_UNSIGNED_BYTE, KTX_FORMAT_LUMINANCE, 1, KTX_DecodeL8 }, + { KTX_TYPE_UNSIGNED_BYTE, KTX_FORMAT_LUMINANCE_ALPHA, 2, KTX_DecodeLA8 }, + { KTX_TYPE_UNSIGNED_BYTE, KTX_FORMAT_BGR, 3, KTX_DecodeBGR8 }, + { KTX_TYPE_UNSIGNED_BYTE, KTX_FORMAT_BGRA, 4, KTX_DecodeBGRA8 }, + { KTX_TYPE_UNSIGNED_SHORT_4_4_4_4, KTX_FORMAT_RGBA, 2, KTX_DecodeRGBA4 }, + { KTX_TYPE_UNSIGNED_SHORT_5_5_5_1, KTX_FORMAT_RGBA, 2, KTX_DecodeRGBA5 }, + { KTX_TYPE_UNSIGNED_SHORT_5_6_5, KTX_FORMAT_RGB, 2, KTX_DecodeRGB5 }, + { 0, 0, 0, NULL } +}; + +static qboolean KTX_DecodeETC1( const byte* in, size_t inSize, unsigned int width, unsigned int height, byte* out ){ + unsigned int y, stride = width * 4; + byte rgba[64]; + + if ( inSize < ( ( ( ( width + 3 ) & ~3 ) * ( ( height + 3 ) & ~3 ) ) >> 1 ) ) { + return qfalse; + } + + for ( y = 0; y < height; y += 4, out += stride * 4 ) + { + byte *p; + unsigned int x, blockrows; + + blockrows = height - y; + if ( blockrows > 4 ) { + blockrows = 4; + } + + p = out; + for ( x = 0; x < width; x += 4, p += 16 ) + { + unsigned int blockrowsize, blockrow; + + ETC_DecodeETC1Block( in, rgba, qtrue ); + in += 8; + + blockrowsize = width - x; + if ( blockrowsize > 4 ) { + blockrowsize = 4; + } + blockrowsize *= 4; + for ( blockrow = 0; blockrow < blockrows; blockrow++ ) + { + memcpy( p + blockrow * stride, rgba + blockrow * 16, blockrowsize ); + } } } + + return qtrue; } +#define KTX_HEADER_UINT32( buf ) ( bigEndian ? KTX_UINT32_BE( buf ) : KTX_UINT32_LE( buf ) ) + +void LoadKTXBufferFirstImage( const byte *buffer, size_t bufSize, byte **pic, int *picWidth, int *picHeight ){ + unsigned int type, format, width, height, imageOffset; + byte *pixels; + + if ( bufSize < 64 ) { + Error( "LoadKTX: Image doesn't have a header" ); + } + + if ( memcmp( buffer, "\xABKTX 11\xBB\r\n\x1A\n", 12 ) ) { + Error( "LoadKTX: Image has the wrong identifier" ); + } + + qboolean bigEndian = ( buffer[4] == 4 ); + + type = KTX_HEADER_UINT32( buffer + 16 ); + if ( type ) { + format = KTX_HEADER_UINT32( buffer + 32 ); + } + else { + format = KTX_HEADER_UINT32( buffer + 28 ); + } + + width = KTX_HEADER_UINT32( buffer + 36 ); + height = KTX_HEADER_UINT32( buffer + 40 ); + if ( !width ) { + Error( "LoadKTX: Image has zero width" ); + } + if ( !height ) { + height = 1; + } + if ( picWidth ) { + *picWidth = width; + } + if ( picHeight ) { + *picHeight = height; + } + + imageOffset = 64 + KTX_HEADER_UINT32( buffer + 60 ) + 4; + if ( bufSize < imageOffset ) { + Error( "LoadKTX: No image in the file" ); + } + buffer += imageOffset; + bufSize -= imageOffset; + + pixels = safe_malloc( width * height * 4 ); + *pic = pixels; + + if ( type ) { + const KTX_UncompressedFormat_t *ktxFormat = KTX_UncompressedFormats; + unsigned int pixelSize; + unsigned int inRowLength, inPadding; + unsigned int y; + + while ( ktxFormat->type ) + { + if ( ktxFormat->type == type && ktxFormat->format == format ) { + break; + } + ktxFormat++; + } + if ( !ktxFormat->type ) { + Error( "LoadKTX: Image has an unsupported pixel type 0x%X or format 0x%X", type, format ); + } + + pixelSize = ktxFormat->pixelSize; + inRowLength = width * pixelSize; + inPadding = ( ( inRowLength + 3 ) & ~3 ) - inRowLength; + + if ( bufSize < height * ( inRowLength + inPadding ) ) { + Error( "LoadKTX: Image is truncated" ); + } + for ( y = 0; y < height; y++ ) + { + unsigned int x; + for ( x = 0; x < width; x++, buffer += pixelSize, pixels += 4 ) + { + ktxFormat->decode( buffer, bigEndian, pixels ); + } + buffer += inPadding; + } + } + else { + qboolean decoded = qfalse; + + switch ( format ) + { + case KTX_FORMAT_ETC1_RGB8: + decoded = KTX_DecodeETC1( buffer, bufSize, width, height, pixels ); + break; + default: + Error( "LoadKTX: Image has an unsupported compressed format format 0x%X", format ); + break; + } + + if ( !decoded ) { + Error( "LoadKTX: Image is truncated" ); + } + } +}