123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 Source Code 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 3 of the License, or
- (at your option) any later version.
- Doom 3 Source Code 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- #include "tr_local.h"
- /*
- This file only has a single entry point:
- void R_LoadImage( const char *name, byte **pic, int *width, int *height, bool makePowerOf2 );
- */
- /*
- * Include file for users of JPEG library.
- * You will need to have included system headers that define at least
- * the typedefs FILE and size_t before you can include jpeglib.h.
- * (stdio.h is sufficient on ANSI-conforming systems.)
- * You may also wish to include "jerror.h".
- */
- extern "C" {
- #include "jpeg-6/jpeglib.h"
- // hooks from jpeg lib to our system
- void jpg_Error( const char *fmt, ... ) {
- va_list argptr;
- char msg[2048];
- va_start (argptr,fmt);
- vsprintf (msg,fmt,argptr);
- va_end (argptr);
- common->FatalError( "%s", msg );
- }
- void jpg_Printf( const char *fmt, ... ) {
- va_list argptr;
- char msg[2048];
- va_start (argptr,fmt);
- vsprintf (msg,fmt,argptr);
- va_end (argptr);
- common->Printf( "%s", msg );
- }
- }
- /*
- ================
- R_WriteTGA
- ================
- */
- void R_WriteTGA( const char *filename, const byte *data, int width, int height, bool flipVertical ) {
- byte *buffer;
- int i;
- int bufferSize = width*height*4 + 18;
- int imgStart = 18;
- buffer = (byte *)Mem_Alloc( bufferSize );
- 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
- if ( !flipVertical ) {
- buffer[17] = (1<<5); // flip bit, for normal top to bottom raster order
- }
- // swap rgb to bgr
- for ( i=imgStart ; i<bufferSize ; i+=4 ) {
- buffer[i] = data[i-imgStart+2]; // blue
- buffer[i+1] = data[i-imgStart+1]; // green
- buffer[i+2] = data[i-imgStart+0]; // red
- buffer[i+3] = data[i-imgStart+3]; // alpha
- }
- fileSystem->WriteFile( filename, buffer, bufferSize );
- Mem_Free (buffer);
- }
- /*
- ================
- R_WritePalTGA
- ================
- */
- void R_WritePalTGA( const char *filename, const byte *data, const byte *palette, int width, int height, bool flipVertical ) {
- byte *buffer;
- int i;
- int bufferSize = (width * height) + (256 * 3) + 18;
- int palStart = 18;
- int imgStart = 18 + (256 * 3);
- buffer = (byte *)Mem_Alloc( bufferSize );
- memset( buffer, 0, 18 );
- buffer[1] = 1; // color map type
- buffer[2] = 1; // uncompressed color mapped image
- buffer[5] = 0; // number of palette entries (lo)
- buffer[6] = 1; // number of palette entries (hi)
- buffer[7] = 24; // color map bpp
- buffer[12] = width&255;
- buffer[13] = width>>8;
- buffer[14] = height&255;
- buffer[15] = height>>8;
- buffer[16] = 8; // pixel size
- if ( !flipVertical ) {
- buffer[17] = (1<<5); // flip bit, for normal top to bottom raster order
- }
- // store palette, swapping rgb to bgr
- for ( i=palStart ; i<imgStart ; i+=3 ) {
- buffer[i] = palette[i-palStart+2]; // blue
- buffer[i+1] = palette[i-palStart+1]; // green
- buffer[i+2] = palette[i-palStart+0]; // red
- }
- // store the image data
- for ( i=imgStart ; i<bufferSize ; i++ ) {
- buffer[i] = data[i-imgStart];
- }
- fileSystem->WriteFile( filename, buffer, bufferSize );
- Mem_Free (buffer);
- }
- static void LoadBMP( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp );
- static void LoadTGA( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp );
- static void LoadJPG( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp );
- /*
- ========================================================================
- PCX files are used for 8 bit images
- ========================================================================
- */
- 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;
- /*
- ========================================================================
- TGA files are used for 24/32 bit images
- ========================================================================
- */
- 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;
- /*
- =========================================================
- BMP LOADING
- =========================================================
- */
- typedef struct
- {
- char id[2];
- unsigned long fileSize;
- unsigned long reserved0;
- unsigned long bitmapDataOffset;
- unsigned long bitmapHeaderSize;
- unsigned long width;
- unsigned long height;
- unsigned short planes;
- unsigned short bitsPerPixel;
- unsigned long compression;
- unsigned long bitmapDataSize;
- unsigned long hRes;
- unsigned long vRes;
- unsigned long colors;
- unsigned long importantColors;
- unsigned char palette[256][4];
- } BMPHeader_t;
- /*
- ==============
- LoadBMP
- ==============
- */
- static void LoadBMP( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp )
- {
- int columns, rows, numPixels;
- byte *pixbuf;
- int row, column;
- byte *buf_p;
- byte *buffer;
- int length;
- BMPHeader_t bmpHeader;
- byte *bmpRGBA;
- if ( !pic ) {
- fileSystem->ReadFile ( name, NULL, timestamp );
- return; // just getting timestamp
- }
- *pic = NULL;
- //
- // load the file
- //
- length = fileSystem->ReadFile( name, (void **)&buffer, timestamp );
- if ( !buffer ) {
- return;
- }
- buf_p = buffer;
- bmpHeader.id[0] = *buf_p++;
- bmpHeader.id[1] = *buf_p++;
- bmpHeader.fileSize = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.reserved0 = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.bitmapDataOffset = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.bitmapHeaderSize = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.width = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.height = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.planes = LittleShort( * ( short * ) buf_p );
- buf_p += 2;
- bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p );
- buf_p += 2;
- bmpHeader.compression = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.bitmapDataSize = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.hRes = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.vRes = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.colors = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.importantColors = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
- if ( bmpHeader.bitsPerPixel == 8 )
- buf_p += 1024;
- if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' )
- {
- common->Error( "LoadBMP: only Windows-style BMP files supported (%s)\n", name );
- }
- if ( bmpHeader.fileSize != length )
- {
- common->Error( "LoadBMP: header size does not match file size (%lu vs. %d) (%s)\n", bmpHeader.fileSize, length, name );
- }
- if ( bmpHeader.compression != 0 )
- {
- common->Error( "LoadBMP: only uncompressed BMP files supported (%s)\n", name );
- }
- if ( bmpHeader.bitsPerPixel < 8 )
- {
- common->Error( "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name );
- }
- columns = bmpHeader.width;
- rows = bmpHeader.height;
- if ( rows < 0 )
- rows = -rows;
- numPixels = columns * rows;
- if ( width )
- *width = columns;
- if ( height )
- *height = rows;
- bmpRGBA = (byte *)R_StaticAlloc( numPixels * 4 );
- *pic = bmpRGBA;
- for ( row = rows-1; row >= 0; row-- )
- {
- pixbuf = bmpRGBA + row*columns*4;
- for ( column = 0; column < columns; column++ )
- {
- unsigned char red, green, blue, alpha;
- int palIndex;
- unsigned short shortPixel;
- switch ( bmpHeader.bitsPerPixel )
- {
- case 8:
- palIndex = *buf_p++;
- *pixbuf++ = bmpHeader.palette[palIndex][2];
- *pixbuf++ = bmpHeader.palette[palIndex][1];
- *pixbuf++ = bmpHeader.palette[palIndex][0];
- *pixbuf++ = 0xff;
- break;
- case 16:
- shortPixel = * ( unsigned short * ) pixbuf;
- pixbuf += 2;
- *pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7;
- *pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2;
- *pixbuf++ = ( shortPixel & ( 31 ) ) << 3;
- *pixbuf++ = 0xff;
- break;
- case 24:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alpha = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = alpha;
- break;
- default:
- common->Error( "LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel, name );
- break;
- }
- }
- }
- fileSystem->FreeFile( buffer );
- }
- /*
- =================================================================
- PCX LOADING
- =================================================================
- */
- /*
- ==============
- LoadPCX
- ==============
- */
- static void LoadPCX ( const char *filename, byte **pic, byte **palette, int *width, int *height,
- ID_TIME_T *timestamp ) {
- byte *raw;
- pcx_t *pcx;
- int x, y;
- int len;
- int dataByte, runLength;
- byte *out, *pix;
- int xmax, ymax;
- if ( !pic ) {
- fileSystem->ReadFile( filename, NULL, timestamp );
- return; // just getting timestamp
- }
- *pic = NULL;
- *palette = NULL;
- //
- // load the file
- //
- len = fileSystem->ReadFile( filename, (void **)&raw, timestamp );
- if (!raw) {
- return;
- }
- //
- // parse the PCX file
- //
- pcx = (pcx_t *)raw;
- raw = &pcx->data;
- xmax = LittleShort(pcx->xmax);
- ymax = LittleShort(pcx->ymax);
- if (pcx->manufacturer != 0x0a
- || pcx->version != 5
- || pcx->encoding != 1
- || pcx->bits_per_pixel != 8
- || xmax >= 1024
- || ymax >= 1024)
- {
- common->Printf( "Bad pcx file %s (%i x %i) (%i x %i)\n", filename, xmax+1, ymax+1, pcx->xmax, pcx->ymax);
- return;
- }
- out = (byte *)R_StaticAlloc( (ymax+1) * (xmax+1) );
- *pic = out;
- pix = out;
- if (palette)
- {
- *palette = (byte *)R_StaticAlloc(768);
- memcpy (*palette, (byte *)pcx + len - 768, 768);
- }
- if (width)
- *width = xmax+1;
- if (height)
- *height = ymax+1;
- // FIXME: use bytes_per_line here?
- for (y=0 ; y<=ymax ; y++, pix += xmax+1)
- {
- for (x=0 ; x<=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)
- {
- common->Printf( "PCX file %s was malformed", filename );
- R_StaticFree (*pic);
- *pic = NULL;
- }
- fileSystem->FreeFile( pcx );
- }
- /*
- ==============
- LoadPCX32
- ==============
- */
- static void LoadPCX32 ( const char *filename, byte **pic, int *width, int *height, ID_TIME_T *timestamp) {
- byte *palette;
- byte *pic8;
- int i, c, p;
- byte *pic32;
- if ( !pic ) {
- fileSystem->ReadFile( filename, NULL, timestamp );
- return; // just getting timestamp
- }
- LoadPCX (filename, &pic8, &palette, width, height, timestamp);
- if (!pic8) {
- *pic = NULL;
- return;
- }
- c = (*width) * (*height);
- pic32 = *pic = (byte *)R_StaticAlloc(4 * c );
- for (i = 0 ; i < c ; i++) {
- p = pic8[i];
- pic32[0] = palette[p*3];
- pic32[1] = palette[p*3 + 1];
- pic32[2] = palette[p*3 + 2];
- pic32[3] = 255;
- pic32 += 4;
- }
- R_StaticFree( pic8 );
- R_StaticFree( palette );
- }
- /*
- =========================================================
- TARGA LOADING
- =========================================================
- */
- /*
- =============
- LoadTGA
- =============
- */
- static void LoadTGA( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp ) {
- int columns, rows, numPixels, fileSize, numBytes;
- byte *pixbuf;
- int row, column;
- byte *buf_p;
- byte *buffer;
- TargaHeader targa_header;
- byte *targa_rgba;
- if ( !pic ) {
- fileSystem->ReadFile( name, NULL, timestamp );
- return; // just getting timestamp
- }
- *pic = NULL;
- //
- // load the file
- //
- fileSize = fileSystem->ReadFile( name, (void **)&buffer, timestamp );
- if ( !buffer ) {
- return;
- }
- buf_p = buffer;
- targa_header.id_length = *buf_p++;
- targa_header.colormap_type = *buf_p++;
- targa_header.image_type = *buf_p++;
-
- targa_header.colormap_index = LittleShort ( *(short *)buf_p );
- buf_p += 2;
- targa_header.colormap_length = LittleShort ( *(short *)buf_p );
- buf_p += 2;
- targa_header.colormap_size = *buf_p++;
- targa_header.x_origin = LittleShort ( *(short *)buf_p );
- buf_p += 2;
- targa_header.y_origin = LittleShort ( *(short *)buf_p );
- buf_p += 2;
- targa_header.width = LittleShort ( *(short *)buf_p );
- buf_p += 2;
- targa_header.height = LittleShort ( *(short *)buf_p );
- buf_p += 2;
- targa_header.pixel_size = *buf_p++;
- targa_header.attributes = *buf_p++;
- if ( targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 ) {
- common->Error( "LoadTGA( %s ): Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n", name );
- }
- if ( targa_header.colormap_type != 0 ) {
- common->Error( "LoadTGA( %s ): colormaps not supported\n", name );
- }
- if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) {
- common->Error( "LoadTGA( %s ): Only 32 or 24 bit images supported (no colormaps)\n", name );
- }
- if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) {
- numBytes = targa_header.width * targa_header.height * ( targa_header.pixel_size >> 3 );
- if ( numBytes > fileSize - 18 - targa_header.id_length ) {
- common->Error( "LoadTGA( %s ): incomplete file\n", name );
- }
- }
- columns = targa_header.width;
- rows = targa_header.height;
- numPixels = columns * rows;
- if ( width ) {
- *width = columns;
- }
- if ( height ) {
- *height = rows;
- }
- targa_rgba = (byte *)R_StaticAlloc(numPixels*4);
- *pic = targa_rgba;
- if ( targa_header.id_length != 0 ) {
- buf_p += targa_header.id_length; // skip TARGA image comment
- }
-
- if ( targa_header.image_type == 2 || targa_header.image_type == 3 )
- {
- // Uncompressed RGB or gray scale image
- 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 8:
- blue = *buf_p++;
- green = blue;
- red = blue;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = 255;
- break;
- case 24:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = alphabyte;
- break;
- default:
- common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size );
- break;
- }
- }
- }
- }
- else if ( targa_header.image_type == 10 ) { // Runlength encoded RGB images
- unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
- red = 0;
- green = 0;
- blue = 0;
- alphabyte = 0xff;
- for( row = rows - 1; row >= 0; row-- ) {
- pixbuf = targa_rgba + row*columns*4;
- for( column = 0; column < columns; ) {
- packetHeader= *buf_p++;
- packetSize = 1 + (packetHeader & 0x7f);
- if ( packetHeader & 0x80 ) { // run-length packet
- switch( targa_header.pixel_size ) {
- case 24:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = *buf_p++;
- break;
- default:
- common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size );
- 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 = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = alphabyte;
- break;
- default:
- common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size );
- 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: ;
- }
- }
- if ( (targa_header.attributes & (1<<5)) ) { // image flp bit
- R_VerticalFlip( *pic, *width, *height );
- }
- fileSystem->FreeFile( buffer );
- }
- /*
- =========================================================
- JPG LOADING
- Interfaces with the huge libjpeg
- =========================================================
- */
- /*
- =============
- LoadJPG
- =============
- */
- static void LoadJPG( const char *filename, unsigned char **pic, int *width, int *height, ID_TIME_T *timestamp ) {
- /* This struct contains the JPEG decompression parameters and pointers to
- * working space (which is allocated as needed by the JPEG library).
- */
- struct jpeg_decompress_struct cinfo;
- /* We use our private extension JPEG error handler.
- * Note that this struct must live as long as the main JPEG parameter
- * struct, to avoid dangling-pointer problems.
- */
- /* This struct represents a JPEG error handler. It is declared separately
- * because applications often want to supply a specialized error handler
- * (see the second half of this file for an example). But here we just
- * take the easy way out and use the standard error handler, which will
- * print a message on stderr and call exit() if compression fails.
- * Note that this struct must live as long as the main JPEG parameter
- * struct, to avoid dangling-pointer problems.
- */
- struct jpeg_error_mgr jerr;
- /* More stuff */
- JSAMPARRAY buffer; /* Output row buffer */
- int row_stride; /* physical row width in output buffer */
- unsigned char *out;
- byte *fbuffer;
- byte *bbuf;
- /* In this example we want to open the input file before doing anything else,
- * so that the setjmp() error recovery below can assume the file is open.
- * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
- * requires it in order to read binary files.
- */
- // JDC: because fill_input_buffer() blindly copies INPUT_BUF_SIZE bytes,
- // we need to make sure the file buffer is padded or it may crash
- if ( pic ) {
- *pic = NULL; // until proven otherwise
- }
- {
- int len;
- idFile *f;
- f = fileSystem->OpenFileRead( filename );
- if ( !f ) {
- return;
- }
- len = f->Length();
- if ( timestamp ) {
- *timestamp = f->Timestamp();
- }
- if ( !pic ) {
- fileSystem->CloseFile( f );
- return; // just getting timestamp
- }
- fbuffer = (byte *)Mem_ClearedAlloc( len + 4096 );
- f->Read( fbuffer, len );
- fileSystem->CloseFile( f );
- }
- /* Step 1: allocate and initialize JPEG decompression object */
- /* We have to set up the error handler first, in case the initialization
- * step fails. (Unlikely, but it could happen if you are out of memory.)
- * This routine fills in the contents of struct jerr, and returns jerr's
- * address which we place into the link field in cinfo.
- */
- cinfo.err = jpeg_std_error(&jerr);
- /* Now we can initialize the JPEG decompression object. */
- jpeg_create_decompress(&cinfo);
- /* Step 2: specify data source (eg, a file) */
- jpeg_stdio_src(&cinfo, fbuffer);
- /* Step 3: read file parameters with jpeg_read_header() */
- (void) jpeg_read_header(&cinfo, true );
- /* We can ignore the return value from jpeg_read_header since
- * (a) suspension is not possible with the stdio data source, and
- * (b) we passed TRUE to reject a tables-only JPEG file as an error.
- * See libjpeg.doc for more info.
- */
- /* Step 4: set parameters for decompression */
- /* In this example, we don't need to change any of the defaults set by
- * jpeg_read_header(), so we do nothing here.
- */
- /* Step 5: Start decompressor */
- (void) jpeg_start_decompress(&cinfo);
- /* We can ignore the return value since suspension is not possible
- * with the stdio data source.
- */
- /* We may need to do some setup of our own at this point before reading
- * the data. After jpeg_start_decompress() we have the correct scaled
- * output image dimensions available, as well as the output colormap
- * if we asked for color quantization.
- * In this example, we need to make an output work buffer of the right size.
- */
- /* JSAMPLEs per row in output buffer */
- row_stride = cinfo.output_width * cinfo.output_components;
- if (cinfo.output_components!=4) {
- common->DWarning( "JPG %s is unsupported color depth (%d)",
- filename, cinfo.output_components);
- }
- out = (byte *)R_StaticAlloc(cinfo.output_width*cinfo.output_height*4);
- *pic = out;
- *width = cinfo.output_width;
- *height = cinfo.output_height;
- /* Step 6: while (scan lines remain to be read) */
- /* jpeg_read_scanlines(...); */
- /* Here we use the library's state variable cinfo.output_scanline as the
- * loop counter, so that we don't have to keep track ourselves.
- */
- while (cinfo.output_scanline < cinfo.output_height) {
- /* jpeg_read_scanlines expects an array of pointers to scanlines.
- * Here the array is only one element long, but you could ask for
- * more than one scanline at a time if that's more convenient.
- */
- bbuf = ((out+(row_stride*cinfo.output_scanline)));
- buffer = &bbuf;
- (void) jpeg_read_scanlines(&cinfo, buffer, 1);
- }
- // clear all the alphas to 255
- {
- int i, j;
- byte *buf;
- buf = *pic;
- j = cinfo.output_width * cinfo.output_height * 4;
- for ( i = 3 ; i < j ; i+=4 ) {
- buf[i] = 255;
- }
- }
- /* Step 7: Finish decompression */
- (void) jpeg_finish_decompress(&cinfo);
- /* We can ignore the return value since suspension is not possible
- * with the stdio data source.
- */
- /* Step 8: Release JPEG decompression object */
- /* This is an important step since it will release a good deal of memory. */
- jpeg_destroy_decompress(&cinfo);
- /* After finish_decompress, we can close the input file.
- * Here we postpone it until after no more JPEG errors are possible,
- * so as to simplify the setjmp error logic above. (Actually, I don't
- * think that jpeg_destroy can do an error exit, but why assume anything...)
- */
- Mem_Free( fbuffer );
- /* At this point you may want to check to see whether any corrupt-data
- * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
- */
- /* And we're done! */
- }
- //===================================================================
- /*
- =================
- R_LoadImage
- Loads any of the supported image types into a cannonical
- 32 bit format.
- Automatically attempts to load .jpg files if .tga files fail to load.
- *pic will be NULL if the load failed.
- Anything that is going to make this into a texture would use
- makePowerOf2 = true, but something loading an image as a lookup
- table of some sort would leave it in identity form.
- It is important to do this at image load time instead of texture load
- time for bump maps.
- Timestamp may be NULL if the value is going to be ignored
- If pic is NULL, the image won't actually be loaded, it will just find the
- timestamp.
- =================
- */
- void R_LoadImage( const char *cname, byte **pic, int *width, int *height, ID_TIME_T *timestamp, bool makePowerOf2 ) {
- idStr name = cname;
- if ( pic ) {
- *pic = NULL;
- }
- if ( timestamp ) {
- *timestamp = 0xFFFFFFFF;
- }
- if ( width ) {
- *width = 0;
- }
- if ( height ) {
- *height = 0;
- }
- name.DefaultFileExtension( ".tga" );
- if (name.Length()<5) {
- return;
- }
- name.ToLower();
- idStr ext;
- name.ExtractFileExtension( ext );
- if ( ext == "tga" ) {
- LoadTGA( name.c_str(), pic, width, height, timestamp ); // try tga first
- if ( ( pic && *pic == 0 ) || ( timestamp && *timestamp == -1 ) ) {
- name.StripFileExtension();
- name.DefaultFileExtension( ".jpg" );
- LoadJPG( name.c_str(), pic, width, height, timestamp );
- }
- } else if ( ext == "pcx" ) {
- LoadPCX32( name.c_str(), pic, width, height, timestamp );
- } else if ( ext == "bmp" ) {
- LoadBMP( name.c_str(), pic, width, height, timestamp );
- } else if ( ext == "jpg" ) {
- LoadJPG( name.c_str(), pic, width, height, timestamp );
- }
- if ( ( width && *width < 1 ) || ( height && *height < 1 ) ) {
- if ( pic && *pic ) {
- R_StaticFree( *pic );
- *pic = 0;
- }
- }
- //
- // convert to exact power of 2 sizes
- //
- if ( pic && *pic && makePowerOf2 ) {
- int w, h;
- int scaled_width, scaled_height;
- byte *resampledBuffer;
- w = *width;
- h = *height;
- for (scaled_width = 1 ; scaled_width < w ; scaled_width<<=1)
- ;
- for (scaled_height = 1 ; scaled_height < h ; scaled_height<<=1)
- ;
- if ( scaled_width != w || scaled_height != h ) {
- if ( globalImages->image_roundDown.GetBool() && scaled_width > w ) {
- scaled_width >>= 1;
- }
- if ( globalImages->image_roundDown.GetBool() && scaled_height > h ) {
- scaled_height >>= 1;
- }
- resampledBuffer = R_ResampleTexture( *pic, w, h, scaled_width, scaled_height );
- R_StaticFree( *pic );
- *pic = resampledBuffer;
- *width = scaled_width;
- *height = scaled_height;
- }
- }
- }
- /*
- =======================
- R_LoadCubeImages
- Loads six files with proper extensions
- =======================
- */
- bool R_LoadCubeImages( const char *imgName, cubeFiles_t extensions, byte *pics[6], int *outSize, ID_TIME_T *timestamp ) {
- int i, j;
- char *cameraSides[6] = { "_forward.tga", "_back.tga", "_left.tga", "_right.tga",
- "_up.tga", "_down.tga" };
- char *axisSides[6] = { "_px.tga", "_nx.tga", "_py.tga", "_ny.tga",
- "_pz.tga", "_nz.tga" };
- char **sides;
- char fullName[MAX_IMAGE_NAME];
- int width, height, size = 0;
- if ( extensions == CF_CAMERA ) {
- sides = cameraSides;
- } else {
- sides = axisSides;
- }
- // FIXME: precompressed cube map files
- if ( pics ) {
- memset( pics, 0, 6*sizeof(pics[0]) );
- }
- if ( timestamp ) {
- *timestamp = 0;
- }
- for ( i = 0 ; i < 6 ; i++ ) {
- idStr::snPrintf( fullName, sizeof( fullName ), "%s%s", imgName, sides[i] );
- ID_TIME_T thisTime;
- if ( !pics ) {
- // just checking timestamps
- R_LoadImageProgram( fullName, NULL, &width, &height, &thisTime );
- } else {
- R_LoadImageProgram( fullName, &pics[i], &width, &height, &thisTime );
- }
- if ( thisTime == FILE_NOT_FOUND_TIMESTAMP ) {
- break;
- }
- if ( i == 0 ) {
- size = width;
- }
- if ( width != size || height != size ) {
- common->Warning( "Mismatched sizes on cube map '%s'", imgName );
- break;
- }
- if ( timestamp ) {
- if ( thisTime > *timestamp ) {
- *timestamp = thisTime;
- }
- }
- if ( pics && extensions == CF_CAMERA ) {
- // convert from "camera" images to native cube map images
- switch( i ) {
- case 0: // forward
- R_RotatePic( pics[i], width);
- break;
- case 1: // back
- R_RotatePic( pics[i], width);
- R_HorizontalFlip( pics[i], width, height );
- R_VerticalFlip( pics[i], width, height );
- break;
- case 2: // left
- R_VerticalFlip( pics[i], width, height );
- break;
- case 3: // right
- R_HorizontalFlip( pics[i], width, height );
- break;
- case 4: // up
- R_RotatePic( pics[i], width);
- break;
- case 5: // down
- R_RotatePic( pics[i], width);
- break;
- }
- }
- }
- if ( i != 6 ) {
- // we had an error, so free everything
- if ( pics ) {
- for ( j = 0 ; j < i ; j++ ) {
- R_StaticFree( pics[j] );
- }
- }
- if ( timestamp ) {
- *timestamp = 0;
- }
- return false;
- }
- if ( outSize ) {
- *outSize = size;
- }
- return true;
- }
|