X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=tools%2Fquake2%2Fcommon%2Flbmlib.c;h=b40b7cb94f320e9d8076aea2914f7395775acddb;hb=e0b3d0ac5abc0cde0a74fadbd2aa4739b43b24a3;hp=e157b94c2f669a3d0377c39b44618ac631319a98;hpb=80378101101ca1762bbf5638a9e3566893096d8a;p=xonotic%2Fnetradiant.git diff --git a/tools/quake2/common/lbmlib.c b/tools/quake2/common/lbmlib.c index e157b94c..b40b7cb9 100644 --- a/tools/quake2/common/lbmlib.c +++ b/tools/quake2/common/lbmlib.c @@ -1,837 +1,849 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -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 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 -*/ -// lbmlib.c - -#include "cmdlib.h" -#include "inout.h" -#include "lbmlib.h" - - - -/* -============================================================================ - - LBM STUFF - -============================================================================ -*/ - - -typedef unsigned char UBYTE; -//conflicts with windows typedef short WORD; -typedef unsigned short UWORD; -typedef long LONG; - -typedef enum -{ - ms_none, - ms_mask, - ms_transcolor, - ms_lasso -} mask_t; - -typedef enum -{ - cm_none, - cm_rle1 -} compress_t; - -typedef struct -{ - 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 - - - -#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; - -int Align (int l) -{ - if (l&1) - return l+1; - return l; -} - - - -/* -================ -LBMRLEdecompress - -Source must be evenly aligned! -================ -*/ -byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth) -{ - int count; - byte b,rept; - - count = 0; - - do - { - rept = *source++; - - if (rept > 0x80) - { - rept = (rept^0xff)+2; - b = *source++; - memset(unpacked,b,rept); - unpacked += rept; - } - else if (rept < 0x80) - { - rept++; - memcpy(unpacked,source,rept); - unpacked += rept; - source += rept; - } - else - rept = 0; // rept of 0x80 is NOP - - count += rept; - - } while (countbpwidth) - Error ("Decompression exceeded width!\n"); - - - return source; -} - - -/* -================= -LoadLBM -================= -*/ -void LoadLBM (char *filename, byte **picture, byte **palette) -{ - byte *LBMbuffer, *picbuffer, *cmapbuffer; - int y; - byte *LBM_P, *LBMEND_P; - byte *pic_p; - byte *body_p; - - int formtype,formlength; - int chunktype,chunklength; - -// qiet compiler warnings - picbuffer = NULL; - cmapbuffer = NULL; - -// -// load the LBM -// - 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"); - - LBM_P += 4; - formlength = BigLong( *(int *)LBM_P ); - LBM_P += 4; - LBMEND_P = LBM_P + Align(formlength); - - 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); - - LBM_P += 4; - -// -// parse chunks -// - - while (LBM_P < LBMEND_P) - { - 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); - 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); - break; - - case CMAPID: - cmapbuffer = malloc (768); - memset (cmapbuffer, 0, 768); - memcpy (cmapbuffer, LBM_P, chunklength); - break; - - case BODYID: - body_p = LBM_P; - - pic_p = picbuffer = 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 = malloc(768); - memcpy (*palette, (byte *)pcx + len - 768, 768); - } - - if (width) - *width = pcx->xmax+1; - if (height) - *height = pcx->ymax+1; - - if (!pic) - return; - - out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); - if (!out) - Error ("Skin_Cache: couldn't allocate"); - - *pic = out; - - pix = out; - - for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1) - { - for (x=0 ; x<=pcx->xmax ; ) - { - dataByte = *raw++; - - if((dataByte & 0xC0) == 0xC0) - { - runLength = dataByte & 0x3F; - dataByte = *raw++; - } - else - runLength = 1; - - while(runLength-- > 0) - pix[x++] = dataByte; - } - - } - - if ( raw - (byte *)pcx > len) - Error ("PCX file %s was malformed", filename); - - free (pcx); -} - -/* -============== -WritePCXfile -============== -*/ -void WritePCXfile (char *filename, byte *data, - int width, int height, byte *palette) -{ - int i, j, length; - pcx_t *pcx; - byte *pack; - - pcx = 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(2); // not a grey scale - - // pack the image - pack = &pcx->data; - - for (i=0 ; i=0; row--) { - pixbuf = targa_rgba + row*columns*4; - for(column=0; column=0; row--) { - pixbuf = targa_rgba + row*columns*4; - for(column=0; column0) - row--; - else - goto breakOut; - pixbuf = targa_rgba + row*columns*4; - } - } - } - else { // non run-length packet - for(j=0;j0) - row--; - else - goto breakOut; - pixbuf = targa_rgba + row*columns*4; - } - } - } - } - breakOut:; - } - } - - // vertically flipped - if ( (targa_header.attributes & (1<<5)) ) { - int flip; - for (row = 0; row < .5f * rows; row++) - { - for (column = 0; column < columns; column++) - { - flip = *( (int*)targa_rgba + row * columns + column); - *( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ); - *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip; - } - } - } - - fclose(fin); -} +/* + 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. + + 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. + + 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 + */ +// lbmlib.c + +#include "cmdlib.h" +#include "inout.h" +#include "lbmlib.h" + + + +/* + ============================================================================ + + LBM STUFF + + ============================================================================ + */ + + +typedef unsigned char UBYTE; +//conflicts with windows typedef short WORD; +typedef unsigned short UWORD; +typedef long LONG; + +typedef enum +{ + ms_none, + ms_mask, + ms_transcolor, + ms_lasso +} mask_t; + +typedef enum +{ + cm_none, + cm_rle1 +} compress_t; + +typedef struct +{ + 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 + + + +#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; + +int Align( int l ){ + if ( l & 1 ) { + return l + 1; + } + return l; +} + + + +/* + ================ + LBMRLEdecompress + + Source must be evenly aligned! + ================ + */ +byte *LBMRLEDecompress( byte *source,byte *unpacked, int bpwidth ){ + int count; + byte b,rept; + + count = 0; + + do + { + rept = *source++; + + if ( rept > 0x80 ) { + rept = ( rept ^ 0xff ) + 2; + b = *source++; + memset( unpacked,b,rept ); + unpacked += rept; + } + else if ( rept < 0x80 ) { + rept++; + memcpy( unpacked,source,rept ); + unpacked += rept; + source += rept; + } + else{ + rept = 0; // rept of 0x80 is NOP + + } + count += rept; + + } while ( count < bpwidth ); + + if ( count > bpwidth ) { + Error( "Decompression exceeded width!\n" ); + } + + + return source; +} + + +/* + ================= + LoadLBM + ================= + */ +void LoadLBM( char *filename, byte **picture, byte **palette ){ + byte *LBMbuffer, *picbuffer, *cmapbuffer; + int y; + byte *LBM_P, *LBMEND_P; + byte *pic_p; + byte *body_p; + + int formtype,formlength; + int chunktype,chunklength; + +// qiet compiler warnings + picbuffer = NULL; + cmapbuffer = NULL; + +// +// load the LBM +// + 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" ); + } + + LBM_P += 4; + formlength = BigLong( *(int *)LBM_P ); + LBM_P += 4; + LBMEND_P = LBM_P + Align( formlength ); + + 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 ); + } + + LBM_P += 4; + +// +// parse chunks +// + + while ( LBM_P < LBMEND_P ) + { + 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 ); + 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 ); + break; + + case CMAPID: + cmapbuffer = malloc( 768 ); + memset( cmapbuffer, 0, 768 ); + memcpy( cmapbuffer, LBM_P, chunklength ); + break; + + case BODYID: + body_p = LBM_P; + + pic_p = picbuffer = malloc( bmhd.w * bmhd.h ); + if ( formtype == PBMID ) { + // + // unpack PBM + // + for ( y = 0 ; y < bmhd.h ; y++, pic_p += bmhd.w ) + { + if ( bmhd.compression == cm_rle1 ) { + body_p = LBMRLEDecompress( (byte *)body_p + , pic_p, bmhd.w ); + } + else if ( bmhd.compression == cm_none ) { + memcpy( pic_p,body_p,bmhd.w ); + body_p += Align( bmhd.w ); + } + } + + } + else + { + // + // unpack ILBM + // + Error( "%s is an interlaced LBM, not packed", filename ); + } + break; + } + + LBM_P += Align( chunklength ); + } + + free( LBMbuffer ); + + *picture = picbuffer; + + if ( palette ) { + *palette = cmapbuffer; + } +} + + +/* + ============================================================================ + + WRITE LBM + + ============================================================================ + */ + +/* + ============== + WriteLBMfile + ============== + */ +void WriteLBMfile( char *filename, byte *data, + int width, int height, byte *palette ){ + byte *lbm, *lbmptr; + int *formlength, *bmhdlength, *cmaplength, *bodylength; + int length; + bmhd_t basebmhd; + + lbm = lbmptr = malloc( width * height + 1000 ); + +// +// start FORM +// + *lbmptr++ = 'F'; + *lbmptr++ = 'O'; + *lbmptr++ = 'R'; + *lbmptr++ = 'M'; + + formlength = (int*)lbmptr; + lbmptr += 4; // leave space for length + + *lbmptr++ = 'P'; + *lbmptr++ = 'B'; + *lbmptr++ = 'M'; + *lbmptr++ = ' '; + +// +// write BMHD +// + *lbmptr++ = 'B'; + *lbmptr++ = 'M'; + *lbmptr++ = 'H'; + *lbmptr++ = 'D'; + + bmhdlength = (int *)lbmptr; + lbmptr += 4; // leave space for length + + memset( &basebmhd,0,sizeof( basebmhd ) ); + basebmhd.w = BigShort( (short)width ); + basebmhd.h = BigShort( (short)height ); + basebmhd.nPlanes = BigShort( 8 ); + basebmhd.xAspect = BigShort( 5 ); + basebmhd.yAspect = BigShort( 6 ); + basebmhd.pageWidth = BigShort( (short)width ); + basebmhd.pageHeight = BigShort( (short)height ); + + memcpy( lbmptr,&basebmhd,sizeof( basebmhd ) ); + lbmptr += sizeof( basebmhd ); + + length = lbmptr - (byte *)bmhdlength - 4; + *bmhdlength = BigLong( length ); + if ( length & 1 ) { + *lbmptr++ = 0; // pad chunk to even offset + + } +// +// write CMAP +// + *lbmptr++ = 'C'; + *lbmptr++ = 'M'; + *lbmptr++ = 'A'; + *lbmptr++ = 'P'; + + cmaplength = (int *)lbmptr; + lbmptr += 4; // leave space for length + + memcpy( lbmptr,palette,768 ); + lbmptr += 768; + + length = lbmptr - (byte *)cmaplength - 4; + *cmaplength = BigLong( length ); + if ( length & 1 ) { + *lbmptr++ = 0; // pad chunk to even offset + + } +// +// write BODY +// + *lbmptr++ = 'B'; + *lbmptr++ = 'O'; + *lbmptr++ = 'D'; + *lbmptr++ = 'Y'; + + bodylength = (int *)lbmptr; + lbmptr += 4; // leave space for length + + memcpy( lbmptr,data,width * height ); + lbmptr += width * height; + + length = lbmptr - (byte *)bodylength - 4; + *bodylength = BigLong( length ); + if ( length & 1 ) { + *lbmptr++ = 0; // pad chunk to even offset + + } +// +// done +// + length = lbmptr - (byte *)formlength - 4; + *formlength = BigLong( length ); + if ( length & 1 ) { + *lbmptr++ = 0; // pad chunk to even offset + + } +// +// write output file +// + SaveFile( filename, lbm, lbmptr - lbm ); + free( lbm ); +} + + +/* + ============================================================================ + + LOAD PCX + + ============================================================================ + */ + +typedef struct +{ + char manufacturer; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin,ymin,xmax,ymax; + unsigned short hres,vres; + unsigned char palette[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; + unsigned char data; // unbounded +} pcx_t; + + +/* + ============== + LoadPCX + ============== + */ +void LoadPCX( char *filename, byte **pic, byte **palette, int *width, int *height ){ + byte *raw; + pcx_t *pcx; + int x, y; + int len; + int dataByte, runLength; + byte *out, *pix; + + // + // load the file + // + len = LoadFile( filename, (void **)&raw ); + + // + // parse the PCX file + // + pcx = (pcx_t *)raw; + raw = &pcx->data; + + 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 = malloc( 768 ); + memcpy( *palette, (byte *)pcx + len - 768, 768 ); + } + + if ( width ) { + *width = pcx->xmax + 1; + } + if ( height ) { + *height = pcx->ymax + 1; + } + + if ( !pic ) { + return; + } + + out = malloc( ( pcx->ymax + 1 ) * ( pcx->xmax + 1 ) ); + if ( !out ) { + Error( "Skin_Cache: couldn't allocate" ); + } + + *pic = out; + + pix = out; + + for ( y = 0 ; y <= pcx->ymax ; y++, pix += pcx->xmax + 1 ) + { + for ( x = 0 ; x <= pcx->xmax ; ) + { + dataByte = *raw++; + + if ( ( dataByte & 0xC0 ) == 0xC0 ) { + runLength = dataByte & 0x3F; + dataByte = *raw++; + } + else{ + runLength = 1; + } + + while ( runLength-- > 0 ) + pix[x++] = dataByte; + } + + } + + if ( raw - (byte *)pcx > len ) { + Error( "PCX file %s was malformed", filename ); + } + + free( pcx ); +} + +/* + ============== + WritePCXfile + ============== + */ +void WritePCXfile( char *filename, byte *data, + int width, int height, byte *palette ){ + int i, j, length; + pcx_t *pcx; + byte *pack; + + pcx = 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( 2 ); // not a grey scale + + // pack the image + pack = &pcx->data; + + for ( i = 0 ; i < height ; i++ ) + { + for ( j = 0 ; j < width ; j++ ) + { + if ( ( *data & 0xc0 ) != 0xc0 ) { + *pack++ = *data++; + } + else + { + *pack++ = 0xc1; + *pack++ = *data++; + } + } + } + + // write the palette + *pack++ = 0x0c; // palette ID byte + for ( i = 0 ; i < 768 ; i++ ) + *pack++ = *palette++; + +// write output file + length = pack - (byte *)pcx; + SaveFile( filename, pcx, length ); + + free( pcx ); +} + + +/* + ============================================================================ + + LOAD IMAGE + + ============================================================================ + */ + +/* + ============== + Load256Image + + Will load either an lbm or pcx, depending on extension. + Any of the return pointers can be NULL if you don't want them. + ============== + */ +void Load256Image( char *name, byte **pixels, byte **palette, + int *width, int *height ){ + char ext[128]; + + ExtractFileExtension( name, ext ); + if ( !Q_strncasecmp( ext, "lbm", strlen( ext ) ) ) { + LoadLBM( name, pixels, palette ); + if ( width ) { + *width = bmhd.w; + } + if ( height ) { + *height = bmhd.h; + } + } + else if ( !Q_strncasecmp( ext, "pcx",strlen( ext ) ) ) { + LoadPCX( name, pixels, palette, width, height ); + } + else{ + Error( "%s doesn't have a known image extension", name ); + } +} + + +/* + ============== + Save256Image + + Will save either an lbm or pcx, depending on extension. + ============== + */ +void Save256Image( char *name, byte *pixels, byte *palette, + int width, int height ){ + char ext[128]; + + ExtractFileExtension( name, ext ); + if ( !Q_strncasecmp( ext, "lbm",strlen( ext ) ) ) { + WriteLBMfile( name, pixels, width, height, palette ); + } + else if ( !Q_strncasecmp( ext, "pcx",strlen( ext ) ) ) { + WritePCXfile( name, pixels, width, height, palette ); + } + else{ + Error( "%s doesn't have a known image extension", name ); + } +} + + + + +/* + ============================================================================ + + TARGA IMAGE + + ============================================================================ + */ + +typedef struct _TargaHeader { + unsigned char id_length, colormap_type, image_type; + unsigned short colormap_index, colormap_length; + unsigned char colormap_size; + unsigned short x_origin, y_origin, width, height; + unsigned char pixel_size, attributes; +} TargaHeader; + +int fgetLittleShort( FILE *f ){ + byte b1, b2; + + b1 = fgetc( f ); + b2 = fgetc( f ); + + return (short)( b1 + b2 * 256 ); +} + +int fgetLittleLong( FILE *f ){ + byte b1, b2, b3, b4; + + b1 = fgetc( f ); + b2 = fgetc( f ); + b3 = fgetc( f ); + b4 = fgetc( f ); + + return b1 + ( b2 << 8 ) + ( b3 << 16 ) + ( b4 << 24 ); +} + + +/* + ============= + LoadTGA + ============= + */ +void LoadTGA( char *name, byte **pixels, int *width, int *height ){ + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + FILE *fin; + byte *targa_rgba; + TargaHeader targa_header; + + fin = fopen( name, "rb" ); + if ( !fin ) { + Error( "Couldn't read %s", name ); + } + + targa_header.id_length = fgetc( fin ); + targa_header.colormap_type = fgetc( fin ); + targa_header.image_type = fgetc( fin ); + + targa_header.colormap_index = fgetLittleShort( fin ); + targa_header.colormap_length = fgetLittleShort( fin ); + targa_header.colormap_size = fgetc( fin ); + targa_header.x_origin = fgetLittleShort( fin ); + targa_header.y_origin = fgetLittleShort( fin ); + targa_header.width = fgetLittleShort( fin ); + targa_header.height = fgetLittleShort( fin ); + targa_header.pixel_size = fgetc( fin ); + targa_header.attributes = fgetc( fin ); + + if ( targa_header.image_type != 2 + && targa_header.image_type != 10 ) { + Error( "LoadTGA: Only type 2 and 10 targa RGB images supported\n" ); + } + + if ( targa_header.colormap_type != 0 + || ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) ) { + Error( "Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n" ); + } + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + if ( width ) { + *width = columns; + } + if ( height ) { + *height = rows; + } + targa_rgba = malloc( numPixels * 4 ); + *pixels = targa_rgba; + + if ( targa_header.id_length != 0 ) { + fseek( fin, targa_header.id_length, SEEK_CUR ); // skip TARGA image comment + + } + if ( targa_header.image_type == 2 ) { // Uncompressed, RGB images + for ( row = rows - 1; row >= 0; row-- ) { + pixbuf = targa_rgba + row * columns * 4; + for ( column = 0; column < columns; column++ ) { + unsigned char red,green,blue,alphabyte; + switch ( targa_header.pixel_size ) { + case 24: + + blue = getc( fin ); + green = getc( fin ); + red = getc( fin ); + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = getc( fin ); + green = getc( fin ); + red = getc( fin ); + alphabyte = getc( fin ); + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + } + } + } + } + else if ( targa_header.image_type == 10 ) { // Runlength encoded RGB images + unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; + for ( row = rows - 1; row >= 0; row-- ) { + pixbuf = targa_rgba + row * columns * 4; + for ( column = 0; column < columns; ) { + packetHeader = getc( fin ); + packetSize = 1 + ( packetHeader & 0x7f ); + if ( packetHeader & 0x80 ) { // run-length packet + switch ( targa_header.pixel_size ) { + case 24: + blue = getc( fin ); + green = getc( fin ); + red = getc( fin ); + alphabyte = 255; + break; + case 32: + blue = getc( fin ); + green = getc( fin ); + red = getc( fin ); + alphabyte = getc( fin ); + break; + } + + for ( j = 0; j < packetSize; j++ ) { + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + column++; + if ( column == columns ) { // run spans across rows + column = 0; + if ( row > 0 ) { + row--; + } + else{ + goto breakOut; + } + pixbuf = targa_rgba + row * columns * 4; + } + } + } + else { // non run-length packet + for ( j = 0; j < packetSize; j++ ) { + switch ( targa_header.pixel_size ) { + case 24: + blue = getc( fin ); + green = getc( fin ); + red = getc( fin ); + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = getc( fin ); + green = getc( fin ); + red = getc( fin ); + alphabyte = getc( fin ); + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + } + column++; + if ( column == columns ) { // pixel packet run spans across rows + column = 0; + if ( row > 0 ) { + row--; + } + else{ + goto breakOut; + } + pixbuf = targa_rgba + row * columns * 4; + } + } + } + } +breakOut:; + } + } + + // vertically flipped + if ( ( targa_header.attributes & ( 1 << 5 ) ) ) { + int flip; + for ( row = 0; row < .5f * rows; row++ ) + { + for ( column = 0; column < columns; column++ ) + { + flip = *( (int*)targa_rgba + row * columns + column ); + *( (int*)targa_rgba + row * columns + column ) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ); + *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip; + } + } + } + + fclose( fin ); +}