Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

imagelib.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 // imagelib.c
00023 
00024 #include "cmdlib.h"
00025 #include "imagelib.h"
00026 
00027 
00028 int fgetLittleShort (FILE *f)
00029 {
00030     byte    b1, b2;
00031 
00032     b1 = fgetc(f);
00033     b2 = fgetc(f);
00034 
00035     return (short)(b1 + b2*256);
00036 }
00037 
00038 int fgetLittleLong (FILE *f)
00039 {
00040     byte    b1, b2, b3, b4;
00041 
00042     b1 = fgetc(f);
00043     b2 = fgetc(f);
00044     b3 = fgetc(f);
00045     b4 = fgetc(f);
00046 
00047     return b1 + (b2<<8) + (b3<<16) + (b4<<24);
00048 }
00049 
00050 
00051 
00052 /*
00053 ============================================================================
00054 
00055                         LBM STUFF
00056 
00057 ============================================================================
00058 */
00059 
00060 
00061 typedef unsigned char   UBYTE;
00062 //conflicts with windows typedef short          WORD;
00063 typedef unsigned short  UWORD;
00064 typedef long            LONG;
00065 
00066 typedef enum
00067 {
00068     ms_none,
00069     ms_mask,
00070     ms_transcolor,
00071     ms_lasso
00072 } mask_t;
00073 
00074 typedef enum
00075 {
00076     cm_none,
00077     cm_rle1
00078 } compress_t;
00079 
00080 typedef struct
00081 {
00082     UWORD       w,h;
00083     short       x,y;
00084     UBYTE       nPlanes;
00085     UBYTE       masking;
00086     UBYTE       compression;
00087     UBYTE       pad1;
00088     UWORD       transparentColor;
00089     UBYTE       xAspect,yAspect;
00090     short       pageWidth,pageHeight;
00091 } bmhd_t;
00092 
00093 extern  bmhd_t  bmhd;                       // will be in native byte order
00094 
00095 
00096 
00097 #define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24))
00098 #define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24))
00099 #define PBMID  ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24))
00100 #define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24))
00101 #define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24))
00102 #define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24))
00103 
00104 
00105 bmhd_t  bmhd;
00106 
00107 int    Align (int l)
00108 {
00109     if (l&1)
00110         return l+1;
00111     return l;
00112 }
00113 
00114 
00115 
00116 /*
00117 ================
00118 LBMRLEdecompress
00119 
00120 Source must be evenly aligned!
00121 ================
00122 */
00123 byte  *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth)
00124 {
00125     int     count;
00126     byte    b,rept;
00127 
00128     count = 0;
00129 
00130     do
00131     {
00132         rept = *source++;
00133 
00134         if (rept > 0x80)
00135         {
00136             rept = (rept^0xff)+2;
00137             b = *source++;
00138             memset(unpacked,b,rept);
00139             unpacked += rept;
00140         }
00141         else if (rept < 0x80)
00142         {
00143             rept++;
00144             memcpy(unpacked,source,rept);
00145             unpacked += rept;
00146             source += rept;
00147         }
00148         else
00149             rept = 0;               // rept of 0x80 is NOP
00150 
00151         count += rept;
00152 
00153     } while (count<bpwidth);
00154 
00155     if (count>bpwidth)
00156         Error ("Decompression exceeded width!\n");
00157 
00158 
00159     return source;
00160 }
00161 
00162 
00163 /*
00164 =================
00165 LoadLBM
00166 =================
00167 */
00168 void LoadLBM (const char *filename, byte **picture, byte **palette)
00169 {
00170     byte    *LBMbuffer, *picbuffer, *cmapbuffer;
00171     int             y;
00172     byte    *LBM_P, *LBMEND_P;
00173     byte    *pic_p;
00174     byte    *body_p;
00175 
00176     int    formtype,formlength;
00177     int    chunktype,chunklength;
00178 
00179 // qiet compiler warnings
00180     picbuffer = NULL;
00181     cmapbuffer = NULL;
00182 
00183 //
00184 // load the LBM
00185 //
00186     LoadFile (filename, (void **)&LBMbuffer);
00187 
00188 //
00189 // parse the LBM header
00190 //
00191     LBM_P = LBMbuffer;
00192     if ( *(int *)LBMbuffer != LittleLong(FORMID) )
00193        Error ("No FORM ID at start of file!\n");
00194 
00195     LBM_P += 4;
00196     formlength = BigLong( *(int *)LBM_P );
00197     LBM_P += 4;
00198     LBMEND_P = LBM_P + Align(formlength);
00199 
00200     formtype = LittleLong(*(int *)LBM_P);
00201 
00202     if (formtype != ILBMID && formtype != PBMID)
00203         Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff
00204         ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff);
00205 
00206     LBM_P += 4;
00207 
00208 //
00209 // parse chunks
00210 //
00211 
00212     while (LBM_P < LBMEND_P)
00213     {
00214         chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24);
00215         LBM_P += 4;
00216         chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24);
00217         LBM_P += 4;
00218 
00219         switch ( chunktype )
00220         {
00221         case BMHDID:
00222             memcpy (&bmhd,LBM_P,sizeof(bmhd));
00223             bmhd.w = BigShort(bmhd.w);
00224             bmhd.h = BigShort(bmhd.h);
00225             bmhd.x = BigShort(bmhd.x);
00226             bmhd.y = BigShort(bmhd.y);
00227             bmhd.pageWidth = BigShort(bmhd.pageWidth);
00228             bmhd.pageHeight = BigShort(bmhd.pageHeight);
00229             break;
00230 
00231         case CMAPID:
00232             cmapbuffer = malloc (768);
00233             memset (cmapbuffer, 0, 768);
00234             memcpy (cmapbuffer, LBM_P, chunklength);
00235             break;
00236 
00237         case BODYID:
00238             body_p = LBM_P;
00239 
00240             pic_p = picbuffer = malloc (bmhd.w*bmhd.h);
00241             if (formtype == PBMID)
00242             {
00243             //
00244             // unpack PBM
00245             //
00246                 for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
00247                 {
00248                     if (bmhd.compression == cm_rle1)
00249                         body_p = LBMRLEDecompress ((byte *)body_p
00250                         , pic_p , bmhd.w);
00251                     else if (bmhd.compression == cm_none)
00252                     {
00253                         memcpy (pic_p,body_p,bmhd.w);
00254                         body_p += Align(bmhd.w);
00255                     }
00256                 }
00257 
00258             }
00259             else
00260             {
00261             //
00262             // unpack ILBM
00263             //
00264                 Error ("%s is an interlaced LBM, not packed", filename);
00265             }
00266             break;
00267         }
00268 
00269         LBM_P += Align(chunklength);
00270     }
00271 
00272     free (LBMbuffer);
00273 
00274     *picture = picbuffer;
00275 
00276     if (palette)
00277         *palette = cmapbuffer;
00278 }
00279 
00280 
00281 /*
00282 ============================================================================
00283 
00284                             WRITE LBM
00285 
00286 ============================================================================
00287 */
00288 
00289 /*
00290 ==============
00291 WriteLBMfile
00292 ==============
00293 */
00294 void WriteLBMfile (const char *filename, byte *data,
00295                    int width, int height, byte *palette)
00296 {
00297     byte    *lbm, *lbmptr;
00298     int    *formlength, *bmhdlength, *cmaplength, *bodylength;
00299     int    length;
00300     bmhd_t  basebmhd;
00301 
00302     lbm = lbmptr = malloc (width*height+1000);
00303 
00304 //
00305 // start FORM
00306 //
00307     *lbmptr++ = 'F';
00308     *lbmptr++ = 'O';
00309     *lbmptr++ = 'R';
00310     *lbmptr++ = 'M';
00311 
00312     formlength = (int*)lbmptr;
00313     lbmptr+=4;                      // leave space for length
00314 
00315     *lbmptr++ = 'P';
00316     *lbmptr++ = 'B';
00317     *lbmptr++ = 'M';
00318     *lbmptr++ = ' ';
00319 
00320 //
00321 // write BMHD
00322 //
00323     *lbmptr++ = 'B';
00324     *lbmptr++ = 'M';
00325     *lbmptr++ = 'H';
00326     *lbmptr++ = 'D';
00327 
00328     bmhdlength = (int *)lbmptr;
00329     lbmptr+=4;                      // leave space for length
00330 
00331     memset (&basebmhd,0,sizeof(basebmhd));
00332     basebmhd.w = BigShort((short)width);
00333     basebmhd.h = BigShort((short)height);
00334     basebmhd.nPlanes = BigShort(8);
00335     basebmhd.xAspect = BigShort(5);
00336     basebmhd.yAspect = BigShort(6);
00337     basebmhd.pageWidth = BigShort((short)width);
00338     basebmhd.pageHeight = BigShort((short)height);
00339 
00340     memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
00341     lbmptr += sizeof(basebmhd);
00342 
00343     length = lbmptr-(byte *)bmhdlength-4;
00344     *bmhdlength = BigLong(length);
00345     if (length&1)
00346         *lbmptr++ = 0;          // pad chunk to even offset
00347 
00348 //
00349 // write CMAP
00350 //
00351     *lbmptr++ = 'C';
00352     *lbmptr++ = 'M';
00353     *lbmptr++ = 'A';
00354     *lbmptr++ = 'P';
00355 
00356     cmaplength = (int *)lbmptr;
00357     lbmptr+=4;                      // leave space for length
00358 
00359     memcpy (lbmptr,palette,768);
00360     lbmptr += 768;
00361 
00362     length = lbmptr-(byte *)cmaplength-4;
00363     *cmaplength = BigLong(length);
00364     if (length&1)
00365         *lbmptr++ = 0;          // pad chunk to even offset
00366 
00367 //
00368 // write BODY
00369 //
00370     *lbmptr++ = 'B';
00371     *lbmptr++ = 'O';
00372     *lbmptr++ = 'D';
00373     *lbmptr++ = 'Y';
00374 
00375     bodylength = (int *)lbmptr;
00376     lbmptr+=4;                      // leave space for length
00377 
00378     memcpy (lbmptr,data,width*height);
00379     lbmptr += width*height;
00380 
00381     length = lbmptr-(byte *)bodylength-4;
00382     *bodylength = BigLong(length);
00383     if (length&1)
00384         *lbmptr++ = 0;          // pad chunk to even offset
00385 
00386 //
00387 // done
00388 //
00389     length = lbmptr-(byte *)formlength-4;
00390     *formlength = BigLong(length);
00391     if (length&1)
00392         *lbmptr++ = 0;          // pad chunk to even offset
00393 
00394 //
00395 // write output file
00396 //
00397     SaveFile (filename, lbm, lbmptr-lbm);
00398     free (lbm);
00399 }
00400 
00401 
00402 /*
00403 ============================================================================
00404 
00405 LOAD PCX
00406 
00407 ============================================================================
00408 */
00409 
00410 typedef struct
00411 {
00412     char    manufacturer;
00413     char    version;
00414     char    encoding;
00415     char    bits_per_pixel;
00416     unsigned short  xmin,ymin,xmax,ymax;
00417     unsigned short  hres,vres;
00418     unsigned char   palette[48];
00419     char    reserved;
00420     char    color_planes;
00421     unsigned short  bytes_per_line;
00422     unsigned short  palette_type;
00423     char    filler[58];
00424     unsigned char   data;           // unbounded
00425 } pcx_t;
00426 
00427 
00428 /*
00429 ==============
00430 LoadPCX
00431 ==============
00432 */
00433 void LoadPCX (const char *filename, byte **pic, byte **palette, int *width, int *height)
00434 {
00435     byte    *raw;
00436     pcx_t   *pcx;
00437     int     x, y;
00438     int     len;
00439     int     dataByte, runLength;
00440     byte    *out, *pix;
00441 
00442     //
00443     // load the file
00444     //
00445     len = LoadFile (filename, (void **)&raw);
00446 
00447     //
00448     // parse the PCX file
00449     //
00450     pcx = (pcx_t *)raw;
00451     raw = &pcx->data;
00452 
00453     pcx->xmin = LittleShort(pcx->xmin);
00454     pcx->ymin = LittleShort(pcx->ymin);
00455     pcx->xmax = LittleShort(pcx->xmax);
00456     pcx->ymax = LittleShort(pcx->ymax);
00457     pcx->hres = LittleShort(pcx->hres);
00458     pcx->vres = LittleShort(pcx->vres);
00459     pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
00460     pcx->palette_type = LittleShort(pcx->palette_type);
00461 
00462     if (pcx->manufacturer != 0x0a
00463         || pcx->version != 5
00464         || pcx->encoding != 1
00465         || pcx->bits_per_pixel != 8
00466         || pcx->xmax >= 640
00467         || pcx->ymax >= 480)
00468         Error ("Bad pcx file %s", filename);
00469     
00470     if (palette)
00471     {
00472         *palette = malloc(768);
00473         memcpy (*palette, (byte *)pcx + len - 768, 768);
00474     }
00475 
00476     if (width)
00477         *width = pcx->xmax+1;
00478     if (height)
00479         *height = pcx->ymax+1;
00480 
00481     if (!pic)
00482         return;
00483 
00484     out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
00485     if (!out)
00486         Error ("Skin_Cache: couldn't allocate");
00487 
00488     *pic = out;
00489 
00490     pix = out;
00491 
00492     for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
00493     {
00494         for (x=0 ; x<=pcx->xmax ; )
00495         {
00496             dataByte = *raw++;
00497 
00498             if((dataByte & 0xC0) == 0xC0)
00499             {
00500                 runLength = dataByte & 0x3F;
00501                 dataByte = *raw++;
00502             }
00503             else
00504                 runLength = 1;
00505 
00506             // FIXME: this shouldn't happen, but it does.  Are we decoding the file wrong?
00507             // Truncate runLength so we don't overrun the end of the buffer
00508             if ( ( y == pcx->ymax ) && ( x + runLength > pcx->xmax + 1 ) ) {
00509                 runLength = pcx->xmax - x + 1;
00510             }
00511 
00512             while(runLength-- > 0)
00513                 pix[x++] = dataByte;
00514         }
00515 
00516     }
00517 
00518     if ( raw - (byte *)pcx > len)
00519         Error ("PCX file %s was malformed", filename);
00520 
00521     free (pcx);
00522 }
00523 
00524 /* 
00525 ============== 
00526 WritePCXfile 
00527 ============== 
00528 */ 
00529 void WritePCXfile (const char *filename, byte *data, 
00530                    int width, int height, byte *palette) 
00531 {
00532     int     i, j, length;
00533     pcx_t   *pcx;
00534     byte        *pack;
00535       
00536     pcx = malloc (width*height*2+1000);
00537     memset (pcx, 0, sizeof(*pcx));
00538 
00539     pcx->manufacturer = 0x0a;   // PCX id
00540     pcx->version = 5;           // 256 color
00541     pcx->encoding = 1;      // uncompressed
00542     pcx->bits_per_pixel = 8;        // 256 color
00543     pcx->xmin = 0;
00544     pcx->ymin = 0;
00545     pcx->xmax = LittleShort((short)(width-1));
00546     pcx->ymax = LittleShort((short)(height-1));
00547     pcx->hres = LittleShort((short)width);
00548     pcx->vres = LittleShort((short)height);
00549     pcx->color_planes = 1;      // chunky image
00550     pcx->bytes_per_line = LittleShort((short)width);
00551     pcx->palette_type = LittleShort(1);     // not a grey scale
00552 
00553     // pack the image
00554     pack = &pcx->data;
00555     
00556     for (i=0 ; i<height ; i++)
00557     {
00558         for (j=0 ; j<width ; j++)
00559         {
00560             if ( (*data & 0xc0) != 0xc0)
00561                 *pack++ = *data++;
00562             else
00563             {
00564                 *pack++ = 0xc1;
00565                 *pack++ = *data++;
00566             }
00567         }
00568     }
00569             
00570     // write the palette
00571     *pack++ = 0x0c; // palette ID byte
00572     for (i=0 ; i<768 ; i++)
00573         *pack++ = *palette++;
00574         
00575 // write output file 
00576     length = pack - (byte *)pcx;
00577     SaveFile (filename, pcx, length);
00578 
00579     free (pcx);
00580 } 
00581  
00582 /*
00583 ============================================================================
00584 
00585 LOAD BMP
00586 
00587 ============================================================================
00588 */
00589 
00590 
00591 /*
00592 
00593 // we can't just use these structures, because
00594 // compiler structure alignment will not be portable
00595 // on this unaligned stuff
00596 
00597 typedef struct tagBITMAPFILEHEADER { // bmfh 
00598         WORD    bfType;             // BM
00599         DWORD   bfSize; 
00600         WORD    bfReserved1; 
00601         WORD    bfReserved2; 
00602         DWORD   bfOffBits; 
00603 } BITMAPFILEHEADER; 
00604  
00605 typedef struct tagBITMAPINFOHEADER{ // bmih 
00606    DWORD  biSize; 
00607    LONG   biWidth; 
00608    LONG   biHeight; 
00609    WORD   biPlanes; 
00610    WORD   biBitCount 
00611    DWORD  biCompression; 
00612    DWORD  biSizeImage; 
00613    LONG   biXPelsPerMeter; 
00614    LONG   biYPelsPerMeter; 
00615    DWORD  biClrUsed; 
00616    DWORD  biClrImportant; 
00617 } BITMAPINFOHEADER; 
00618  
00619 typedef struct tagBITMAPINFO { // bmi 
00620    BITMAPINFOHEADER bmiHeader; 
00621    RGBQUAD          bmiColors[1]; 
00622 } BITMAPINFO; 
00623 
00624 typedef struct tagBITMAPCOREHEADER { // bmch 
00625         DWORD   bcSize; 
00626         WORD    bcWidth; 
00627         WORD    bcHeight; 
00628         WORD    bcPlanes; 
00629         WORD    bcBitCount; 
00630 } BITMAPCOREHEADER; 
00631  
00632 typedef struct _BITMAPCOREINFO {    // bmci 
00633         BITMAPCOREHEADER  bmciHeader; 
00634         RGBTRIPLE         bmciColors[1]; 
00635 } BITMAPCOREINFO; 
00636  
00637 */
00638 
00639 /*
00640 ==============
00641 LoadBMP
00642 ==============
00643 */
00644 void LoadBMP (const char *filename, byte **pic, byte **palette, int *width, int *height)
00645 {
00646     byte    *out;
00647     FILE    *fin;
00648     int     i;
00649     int     bfSize; 
00650     int     bfOffBits; 
00651     int     structSize;
00652     int     bcWidth; 
00653     int     bcHeight; 
00654     int     bcPlanes; 
00655     int     bcBitCount; 
00656     byte    bcPalette[1024];
00657     qboolean    flipped;
00658 
00659     fin = fopen (filename, "rb");
00660     if (!fin) {
00661         Error ("Couldn't read %s", filename);
00662     }
00663 
00664     i = fgetLittleShort (fin);
00665     if (i != 'B' + ('M'<<8) ) {
00666         Error ("%s is not a bmp file", filename);
00667     }
00668 
00669     bfSize = fgetLittleLong (fin);
00670     fgetLittleShort(fin);
00671     fgetLittleShort(fin);
00672     bfOffBits = fgetLittleLong (fin);
00673 
00674     // the size will tell us if it is a
00675     // bitmapinfo or a bitmapcore
00676     structSize = fgetLittleLong (fin);
00677     if (structSize == 40) {
00678         // bitmapinfo
00679         bcWidth = fgetLittleLong(fin); 
00680         bcHeight= fgetLittleLong(fin); 
00681         bcPlanes = fgetLittleShort(fin); 
00682         bcBitCount = fgetLittleShort(fin); 
00683 
00684         fseek (fin, 24, SEEK_CUR);
00685 
00686         if (palette) {
00687             fread (bcPalette, 1, 1024, fin);
00688             *palette = malloc(768);
00689 
00690             for (i = 0 ; i < 256 ; i++) {
00691                 (*palette)[i * 3 + 0] = bcPalette[i * 4 + 2];
00692                 (*palette)[i * 3 + 1] = bcPalette[i * 4 + 1];
00693                 (*palette)[i * 3 + 2] = bcPalette[i * 4 + 0];
00694             }
00695         }
00696     } else if (structSize == 12) {
00697         // bitmapcore
00698         bcWidth = fgetLittleShort(fin); 
00699         bcHeight= fgetLittleShort(fin); 
00700         bcPlanes = fgetLittleShort(fin); 
00701         bcBitCount = fgetLittleShort(fin); 
00702 
00703         if (palette) {
00704             fread (bcPalette, 1, 768, fin);
00705             *palette = malloc(768);
00706 
00707             for (i = 0 ; i < 256 ; i++) {
00708                 (*palette)[i * 3 + 0] = bcPalette[i * 3 + 2];
00709                 (*palette)[i * 3 + 1] = bcPalette[i * 3 + 1];
00710                 (*palette)[i * 3 + 2] = bcPalette[i * 3 + 0];
00711             }
00712         }
00713     } else {
00714         Error ("%s had strange struct size", filename);
00715     }
00716     
00717     if (bcPlanes != 1) {
00718         Error ("%s was not a single plane image", filename);
00719     }
00720 
00721     if (bcBitCount != 8) {
00722         Error ("%s was not an 8 bit image", filename);
00723     }
00724 
00725     if (bcHeight < 0) {
00726         bcHeight = -bcHeight;
00727         flipped = qtrue;
00728     } else {
00729         flipped = qfalse;
00730     }
00731 
00732     if (width)
00733         *width = bcWidth;
00734     if (height)
00735         *height = bcHeight;
00736 
00737     if (!pic) {
00738         fclose (fin);
00739         return;
00740     }
00741 
00742     out = malloc ( bcWidth * bcHeight );
00743     *pic = out;
00744     fseek (fin, bfOffBits, SEEK_SET);
00745 
00746     if (flipped) {
00747         for (i = 0 ; i < bcHeight ; i++) {
00748             fread (out + bcWidth * (bcHeight - 1 - i), 1, bcWidth, fin);
00749         }
00750     } else {
00751         fread (out, 1, bcWidth*bcHeight, fin);
00752     }
00753 
00754     fclose (fin);
00755 }
00756 
00757 
00758 /*
00759 ============================================================================
00760 
00761 LOAD IMAGE
00762 
00763 ============================================================================
00764 */
00765 
00766 /*
00767 ==============
00768 Load256Image
00769 
00770 Will load either an lbm or pcx, depending on extension.
00771 Any of the return pointers can be NULL if you don't want them.
00772 ==============
00773 */
00774 void Load256Image (const char *name, byte **pixels, byte **palette,
00775                    int *width, int *height)
00776 {
00777     char    ext[128];
00778 
00779     ExtractFileExtension (name, ext);
00780     if (!Q_stricmp (ext, "lbm"))
00781     {
00782         LoadLBM (name, pixels, palette);
00783         if (width)
00784             *width = bmhd.w;
00785         if (height)
00786             *height = bmhd.h;
00787     }
00788     else if (!Q_stricmp (ext, "pcx"))
00789     {
00790         LoadPCX (name, pixels, palette, width, height);
00791     }
00792     else if (!Q_stricmp (ext, "bmp"))
00793     {
00794         LoadBMP (name, pixels, palette, width, height);
00795     }
00796     else
00797         Error ("%s doesn't have a known image extension", name);
00798 }
00799 
00800 
00801 /*
00802 ==============
00803 Save256Image
00804 
00805 Will save either an lbm or pcx, depending on extension.
00806 ==============
00807 */
00808 void Save256Image (const char *name, byte *pixels, byte *palette,
00809                    int width, int height)
00810 {
00811     char    ext[128];
00812 
00813     ExtractFileExtension (name, ext);
00814     if (!Q_stricmp (ext, "lbm"))
00815     {
00816         WriteLBMfile (name, pixels, width, height, palette);
00817     }
00818     else if (!Q_stricmp (ext, "pcx"))
00819     {
00820         WritePCXfile (name, pixels, width, height, palette);
00821     }
00822     else
00823         Error ("%s doesn't have a known image extension", name);
00824 }
00825 
00826 
00827 
00828 
00829 /*
00830 ============================================================================
00831 
00832 TARGA IMAGE
00833 
00834 ============================================================================
00835 */
00836 
00837 typedef struct _TargaHeader {
00838     unsigned char   id_length, colormap_type, image_type;
00839     unsigned short  colormap_index, colormap_length;
00840     unsigned char   colormap_size;
00841     unsigned short  x_origin, y_origin, width, height;
00842     unsigned char   pixel_size, attributes;
00843 } TargaHeader;
00844 
00845 /*
00846 =============
00847 LoadTGABuffer
00848 =============
00849 */
00850 void LoadTGABuffer ( byte *buffer, byte **pic, int *width, int *height)
00851 {
00852     int     columns, rows, numPixels;
00853     byte    *pixbuf;
00854     int     row, column;
00855     byte    *buf_p;
00856     TargaHeader targa_header;
00857     byte        *targa_rgba;
00858 
00859     *pic = NULL;
00860 
00861     buf_p = buffer;
00862 
00863     targa_header.id_length = *buf_p++;
00864     targa_header.colormap_type = *buf_p++;
00865     targa_header.image_type = *buf_p++;
00866     
00867     targa_header.colormap_index = LittleShort ( *(short *)buf_p );
00868     buf_p += 2;
00869     targa_header.colormap_length = LittleShort ( *(short *)buf_p );
00870     buf_p += 2;
00871     targa_header.colormap_size = *buf_p++;
00872     targa_header.x_origin = LittleShort ( *(short *)buf_p );
00873     buf_p += 2;
00874     targa_header.y_origin = LittleShort ( *(short *)buf_p );
00875     buf_p += 2;
00876     targa_header.width = LittleShort ( *(short *)buf_p );
00877     buf_p += 2;
00878     targa_header.height = LittleShort ( *(short *)buf_p );
00879     buf_p += 2;
00880     targa_header.pixel_size = *buf_p++;
00881     targa_header.attributes = *buf_p++;
00882 
00883     if (targa_header.image_type!=2 
00884         && targa_header.image_type!=10
00885         && targa_header.image_type != 3 ) 
00886     {
00887         Error("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
00888     }
00889 
00890     if ( targa_header.colormap_type != 0 )
00891     {
00892         Error("LoadTGA: colormaps not supported\n" );
00893     }
00894 
00895     if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 )
00896     {
00897         Error("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
00898     }
00899 
00900     columns = targa_header.width;
00901     rows = targa_header.height;
00902     numPixels = columns * rows;
00903 
00904     if (width)
00905         *width = columns;
00906     if (height)
00907         *height = rows;
00908 
00909     targa_rgba = malloc (numPixels*4);
00910     *pic = targa_rgba;
00911 
00912     if (targa_header.id_length != 0)
00913         buf_p += targa_header.id_length;  // skip TARGA image comment
00914     
00915     if ( targa_header.image_type==2 || targa_header.image_type == 3 )
00916     { 
00917         // Uncompressed RGB or gray scale image
00918         for(row=rows-1; row>=0; row--) 
00919         {
00920             pixbuf = targa_rgba + row*columns*4;
00921             for(column=0; column<columns; column++) 
00922             {
00923                 unsigned char red,green,blue,alphabyte;
00924                 switch (targa_header.pixel_size) 
00925                 {
00926                     
00927                 case 8:
00928                     blue = *buf_p++;
00929                     green = blue;
00930                     red = blue;
00931                     *pixbuf++ = red;
00932                     *pixbuf++ = green;
00933                     *pixbuf++ = blue;
00934                     *pixbuf++ = 255;
00935                     break;
00936 
00937                 case 24:
00938                     blue = *buf_p++;
00939                     green = *buf_p++;
00940                     red = *buf_p++;
00941                     *pixbuf++ = red;
00942                     *pixbuf++ = green;
00943                     *pixbuf++ = blue;
00944                     *pixbuf++ = 255;
00945                     break;
00946                 case 32:
00947                     blue = *buf_p++;
00948                     green = *buf_p++;
00949                     red = *buf_p++;
00950                     alphabyte = *buf_p++;
00951                     *pixbuf++ = red;
00952                     *pixbuf++ = green;
00953                     *pixbuf++ = blue;
00954                     *pixbuf++ = alphabyte;
00955                     break;
00956                 default:
00957                     //Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
00958                     break;
00959                 }
00960             }
00961         }
00962     }
00963     else if (targa_header.image_type==10) {   // Runlength encoded RGB images
00964         unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
00965 
00966         red = 0;
00967         green = 0;
00968         blue = 0;
00969         alphabyte = 0xff;
00970 
00971         for(row=rows-1; row>=0; row--) {
00972             pixbuf = targa_rgba + row*columns*4;
00973             for(column=0; column<columns; ) {
00974                 packetHeader= *buf_p++;
00975                 packetSize = 1 + (packetHeader & 0x7f);
00976                 if (packetHeader & 0x80) {        // run-length packet
00977                     switch (targa_header.pixel_size) {
00978                         case 24:
00979                                 blue = *buf_p++;
00980                                 green = *buf_p++;
00981                                 red = *buf_p++;
00982                                 alphabyte = 255;
00983                                 break;
00984                         case 32:
00985                                 blue = *buf_p++;
00986                                 green = *buf_p++;
00987                                 red = *buf_p++;
00988                                 alphabyte = *buf_p++;
00989                                 break;
00990                         default:
00991                             //Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
00992                             break;
00993                     }
00994     
00995                     for(j=0;j<packetSize;j++) {
00996                         *pixbuf++=red;
00997                         *pixbuf++=green;
00998                         *pixbuf++=blue;
00999                         *pixbuf++=alphabyte;
01000                         column++;
01001                         if (column==columns) { // run spans across rows
01002                             column=0;
01003                             if (row>0)
01004                                 row--;
01005                             else
01006                                 goto breakOut;
01007                             pixbuf = targa_rgba + row*columns*4;
01008                         }
01009                     }
01010                 }
01011                 else {                            // non run-length packet
01012                     for(j=0;j<packetSize;j++) {
01013                         switch (targa_header.pixel_size) {
01014                             case 24:
01015                                     blue = *buf_p++;
01016                                     green = *buf_p++;
01017                                     red = *buf_p++;
01018                                     *pixbuf++ = red;
01019                                     *pixbuf++ = green;
01020                                     *pixbuf++ = blue;
01021                                     *pixbuf++ = 255;
01022                                     break;
01023                             case 32:
01024                                     blue = *buf_p++;
01025                                     green = *buf_p++;
01026                                     red = *buf_p++;
01027                                     alphabyte = *buf_p++;
01028                                     *pixbuf++ = red;
01029                                     *pixbuf++ = green;
01030                                     *pixbuf++ = blue;
01031                                     *pixbuf++ = alphabyte;
01032                                     break;
01033                             default:
01034                                 //Sys_Printf("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
01035                                 break;
01036                         }
01037                         column++;
01038                         if (column==columns) { // pixel packet run spans across rows
01039                             column=0;
01040                             if (row>0)
01041                                 row--;
01042                             else
01043                                 goto breakOut;
01044                             pixbuf = targa_rgba + row*columns*4;
01045                         }                       
01046                     }
01047                 }
01048             }
01049             breakOut:;
01050         }
01051     }
01052 
01053     //free(buffer);
01054 }
01055 
01056 
01057 
01058 /*
01059 =============
01060 LoadTGA
01061 =============
01062 */
01063 void LoadTGA (const char *name, byte **pixels, int *width, int *height)
01064 {
01065     byte            *buffer;
01066   int nLen;
01067     //
01068     // load the file
01069     //
01070     nLen = LoadFile ( ( char * ) name, (void **)&buffer);
01071     if (nLen == -1) 
01072   {
01073         Error ("Couldn't read %s", name);
01074   }
01075 
01076   LoadTGABuffer(buffer, pixels, width, height);
01077 
01078 }
01079 
01080 
01081 /*
01082 ================
01083 WriteTGA
01084 ================
01085 */
01086 void WriteTGA (const char *filename, byte *data, int width, int height) {
01087     byte    *buffer;
01088     int     i;
01089     int     c;
01090     FILE    *f;
01091 
01092     buffer = malloc(width*height*4 + 18);
01093     memset (buffer, 0, 18);
01094     buffer[2] = 2;      // uncompressed type
01095     buffer[12] = width&255;
01096     buffer[13] = width>>8;
01097     buffer[14] = height&255;
01098     buffer[15] = height>>8;
01099     buffer[16] = 32;    // pixel size
01100 
01101     // swap rgb to bgr
01102     c = 18 + width * height * 4;
01103     for (i=18 ; i<c ; i+=4)
01104     {
01105         buffer[i] = data[i-18+2];       // blue
01106         buffer[i+1] = data[i-18+1];     // green
01107         buffer[i+2] = data[i-18+0];     // red
01108         buffer[i+3] = data[i-18+3];     // alpha
01109     }
01110 
01111     f = fopen (filename, "wb");
01112     fwrite (buffer, 1, c, f);
01113     fclose (f);
01114 
01115     free (buffer);
01116 }
01117 
01118 /*
01119 ============================================================================
01120 
01121 LOAD32BITIMAGE
01122 
01123 ============================================================================
01124 */
01125 
01126 /*
01127 ==============
01128 Load32BitImage
01129 
01130 Any of the return pointers can be NULL if you don't want them.
01131 ==============
01132 */
01133 void Load32BitImage (const char *name, unsigned **pixels,  int *width, int *height)
01134 {
01135     char    ext[128];
01136     byte    *palette;
01137     byte    *pixels8;
01138     byte    *pixels32;
01139     int     size;
01140     int     i;
01141     int     v;
01142 
01143     ExtractFileExtension (name, ext);
01144     if (!Q_stricmp (ext, "tga")) {
01145         LoadTGA (name, (byte **)pixels, width, height);
01146     } else {
01147         Load256Image (name, &pixels8, &palette, width, height);
01148         if (!pixels) {
01149             return;
01150         }
01151         size = *width * *height;
01152         pixels32 = malloc(size * 4);
01153         *pixels = (unsigned *)pixels32;
01154         for (i = 0 ; i < size ; i++) {
01155             v = pixels8[i];
01156             pixels32[i*4 + 0] = palette[ v * 3 + 0 ];
01157             pixels32[i*4 + 1] = palette[ v * 3 + 1 ];
01158             pixels32[i*4 + 2] = palette[ v * 3 + 2 ];
01159             pixels32[i*4 + 3] = 0xff;
01160         }
01161     }
01162 }
01163 
01164 

Generated on Thu Aug 25 12:38:07 2005 for Quake III Arena by  doxygen 1.3.9.1