summaryrefslogtreecommitdiff
path: root/source/r_images.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/r_images.c')
-rw-r--r--source/r_images.c1095
1 files changed, 583 insertions, 512 deletions
diff --git a/source/r_images.c b/source/r_images.c
index 8468c61..e62ab39 100644
--- a/source/r_images.c
+++ b/source/r_images.c
@@ -33,7 +33,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#if !USE_PNG
#include <setjmp.h>
#endif
-#include <stdio.h>
#include <jpeglib.h>
#endif
@@ -57,12 +56,13 @@ PCX LOADING
IMG_LoadPCX
==============
*/
-qboolean IMG_LoadPCX( const char *filename, byte **pic, byte *palette, int *width, int *height ) {
+qerror_t IMG_LoadPCX( const char *filename, byte **pic, byte *palette, int *width, int *height ) {
byte *raw, *end;
dpcx_t *pcx;
size_t len, x, y, w, h;
int dataByte, runLength;
byte *out, *pix;
+ qerror_t ret;
if( !filename ) {
Com_Error( ERR_FATAL, "LoadPCX: NULL" );
@@ -76,23 +76,26 @@ qboolean IMG_LoadPCX( const char *filename, byte **pic, byte *palette, int *widt
//
len = FS_LoadFile( filename, (void **)&pcx );
if( !pcx ) {
- return qfalse;
- }
- if( len < sizeof( *pcx ) ) {
- Com_WPrintf( "LoadPCX: %s: file too short\n", filename );
- goto fail2;
+ return len;
}
//
// parse the PCX file
//
+ if( len < sizeof( *pcx ) ) {
+ ret = Q_ERR_FILE_TOO_SMALL;
+ goto fail2;
+ }
+
+ if( pcx->manufacturer != 0x0a || pcx->version != 5 ) {
+ ret = Q_ERR_UNKNOWN_FORMAT;
+ goto fail2;
+ }
+
w = LittleShort( pcx->xmax ) + 1;
h = LittleShort( pcx->ymax ) + 1;
- if( pcx->manufacturer != 0x0a || pcx->version != 5
- || pcx->encoding != 1 || pcx->bits_per_pixel != 8
- || w > 640 || h > 480 )
- {
- Com_WPrintf( "LoadPCX: %s: unsupported format\n", filename );
+ if( pcx->encoding != 1 || pcx->bits_per_pixel != 8 || w > 640 || h > 480 ) {
+ ret = Q_ERR_INVALID_FORMAT;
goto fail2;
}
@@ -101,7 +104,7 @@ qboolean IMG_LoadPCX( const char *filename, byte **pic, byte *palette, int *widt
//
if( palette ) {
if( len < 768 ) {
- Com_WPrintf( "LoadPCX: %s: palette too short\n", filename );
+ ret = Q_ERR_FILE_TOO_SMALL;
goto fail2;
}
memcpy( palette, ( byte * )pcx + len - 768, 768 );
@@ -119,7 +122,7 @@ qboolean IMG_LoadPCX( const char *filename, byte **pic, byte *palette, int *widt
for( y = 0; y < h; y++, pix += w ) {
for( x = 0; x < w; ) {
if( raw >= end ) {
- Com_WPrintf( "LoadPCX: %s: read past end of file\n", filename );
+ ret = Q_ERR_BAD_EXTENT;
goto fail1;
}
dataByte = *raw++;
@@ -127,11 +130,11 @@ qboolean IMG_LoadPCX( const char *filename, byte **pic, byte *palette, int *widt
if( ( dataByte & 0xC0 ) == 0xC0 ) {
runLength = dataByte & 0x3F;
if( x + runLength > w ) {
- Com_WPrintf( "LoadPCX: %s: run length overrun\n", filename );
+ ret = Q_ERR_BAD_RLE_PACKET;
goto fail1;
}
if( raw >= end ) {
- Com_WPrintf( "LoadPCX: %s: read past end of file\n", filename );
+ ret = Q_ERR_BAD_RLE_PACKET;
goto fail1;
}
dataByte = *raw++;
@@ -153,28 +156,29 @@ qboolean IMG_LoadPCX( const char *filename, byte **pic, byte *palette, int *widt
*height = h;
FS_FreeFile( pcx );
- return qtrue;
+ return Q_ERR_SUCCESS;
fail1:
IMG_FreePixels( out );
fail2:
FS_FreeFile( pcx );
- return qfalse;
+ return ret;
}
+#if 0
/*
==============
-IMG_WritePCX
+IMG_SavePCX
==============
*/
-qboolean IMG_WritePCX( const char *filename, const byte *data, int width,
+qerror_t IMG_SavePCX( const char *filename, const byte *data, int width,
int height, int rowbytes, byte *palette )
{
- int i, j, length;
+ int i, j;
+ size_t len;
dpcx_t *pcx;
byte *pack;
- qboolean ret = qfalse;
- fileHandle_t f;
+ qerror_t ret;
pcx = FS_AllocTempMem( width * height * 2 + 1000 );
pcx->manufacturer = 0x0a; // PCX id
@@ -209,247 +213,237 @@ qboolean IMG_WritePCX( const char *filename, const byte *data, int width,
*pack++ = 0x0c; // palette ID byte
for( i = 0; i < 768; i++ )
*pack++ = *palette++;
-
+
// write output file
- FS_FOpenFile( filename, &f, FS_MODE_WRITE );
- if( !f ) {
- goto fail;
- }
-
- length = pack - ( byte * )pcx;
- if( FS_Write( pcx, length, f ) == length ) {
- ret = qtrue;
- }
-
- FS_FCloseFile( f );
-
-fail:
+ len = pack - ( byte * )pcx;
+ ret = FS_WriteFile( filename, pcx, len );
FS_FreeFile( pcx );
+
return ret;
-}
+}
+#endif
#if USE_TGA
/*
=========================================================
-TARGA LOADING
+TARGA IMAGES
=========================================================
*/
+#define TARGA_HEADER_SIZE 18
+
#define TGA_DECODE( x ) \
- static qboolean tga_decode_##x( byte *data, byte *pixels, \
- int columns, int rows, byte *maxp )
+ static qerror_t tga_decode_##x( byte *in, byte *out, int cols, int rows, byte *max_in )
-typedef qboolean (*tga_decode_t)( byte *, byte *, int, int, byte * );
+typedef qerror_t (*tga_decode_t)( byte *, byte *, int, int, byte * );
TGA_DECODE( bgr ) {
int col, row;
- uint32_t *pixbuf;
+ byte *out_row;
for( row = rows - 1; row >= 0; row-- ) {
- pixbuf = ( uint32_t * )pixels + row * columns;
-
- for( col = 0; col < columns; col++ ) {
- *pixbuf++ = MakeColor( data[2], data[1], data[0], 255 );
- data += 3;
+ out_row = out + row * cols * 4;
+ for( col = 0; col < cols; col++, out_row += 4, in += 3 ) {
+ out_row[0] = in[2];
+ out_row[1] = in[1];
+ out_row[2] = in[0];
+ out_row[3] = 255;
}
}
- return qtrue;
+ return Q_ERR_SUCCESS;
}
TGA_DECODE( bgra ) {
int col, row;
- uint32_t *pixbuf;
+ byte *out_row;
for( row = rows - 1; row >= 0; row-- ) {
- pixbuf = ( uint32_t * )pixels + row * columns;
-
- for( col = 0; col < columns; col++ ) {
- *pixbuf++ = MakeColor( data[2], data[1], data[0], data[3] );
- data += 4;
+ out_row = out + row * cols * 4;
+ for( col = 0; col < cols; col++, out_row += 4, in += 4 ) {
+ out_row[0] = in[2];
+ out_row[1] = in[1];
+ out_row[2] = in[0];
+ out_row[3] = in[3];
}
}
- return qtrue;
+ return Q_ERR_SUCCESS;
}
TGA_DECODE( bgr_flip ) {
- int count;
- uint32_t *pixbuf;
+ int i, count = rows * cols;
- pixbuf = ( uint32_t * )pixels;
- count = rows * columns;
- do {
- *pixbuf++ = MakeColor( data[2], data[1], data[0], 255 );
- data += 3;
- } while( --count );
+ for( i = 0; i < count; i++, out += 4, in += 3 ) {
+ out[0] = in[2];
+ out[1] = in[1];
+ out[2] = in[0];
+ out[3] = 255;
+ }
- return qtrue;
+ return Q_ERR_SUCCESS;
}
TGA_DECODE( bgra_flip ) {
- int count;
- uint32_t *pixbuf;
+ int i, count = rows * cols;
- pixbuf = ( uint32_t * )pixels;
- count = rows * columns;
- do {
- *pixbuf++ = MakeColor( data[2], data[1], data[0], data[3] );
- data += 4;
- } while( --count );
+ for( i = 0; i < count; i++, out += 4, in += 3 ) {
+ out[0] = in[2];
+ out[1] = in[1];
+ out[2] = in[0];
+ out[3] = in[3];
+ }
- return qtrue;
+ return Q_ERR_SUCCESS;
}
TGA_DECODE( bgr_rle ) {
int col, row;
- uint32_t *pixbuf, color;
- byte packetHeader, packetSize;
+ byte *out_row;
+ uint32_t color;
+ unsigned packet_header, packet_size;
int j;
for( row = rows - 1; row >= 0; row-- ) {
- pixbuf = ( uint32_t * )pixels + row * columns;
+ out_row = out + row * cols * 4;
- for( col = 0; col < columns; ) {
- packetHeader = *data++;
- packetSize = 1 + ( packetHeader & 0x7f );
+ for( col = 0; col < cols; ) {
+ packet_header = *in++;
+ packet_size = 1 + ( packet_header & 0x7f );
- if( packetHeader & 0x80 ) {
- /* run-length packet */
- if( data + 3 > maxp ) {
- return qfalse;
+ if( packet_header & 0x80 ) {
+ // run-length packet
+ if( in + 3 > max_in ) {
+ return Q_ERR_BAD_RLE_PACKET;
}
- color = MakeColor( data[2], data[1], data[0], 255 );
- data += 3;
- for( j = 0; j < packetSize; j++ ) {
- *pixbuf++ = color;
-
- col++;
- if( col == columns ) {
- /* run spans across rows */
+ color = MakeColor( in[2], in[1], in[0], 255 );
+ in += 3;
+ for( j = 0; j < packet_size; j++ ) {
+ *(uint32_t *)out_row = color;
+ out_row += 4;
+
+ if( ++col == cols ) {
+ // run spans across rows
col = 0;
-
if( row > 0 )
row--;
else
- goto breakOut;
-
- pixbuf = ( uint32_t * )pixels + row * columns;
+ goto break_out;
+ out_row = out + row * cols * 4;
}
}
} else {
- /* non run-length packet */
- if( data + 3 * packetSize > maxp ) {
- return qfalse;
+ // non run-length packet
+ if( in + 3 * packet_size > max_in ) {
+ return Q_ERR_BAD_RLE_PACKET;
}
- for( j = 0; j < packetSize; j++ ) {
- *pixbuf++ = MakeColor( data[2], data[1], data[0], 255 );
- data += 3;
-
- col++;
- if( col == columns ) {
- /* run spans across rows */
+ for( j = 0; j < packet_size; j++ ) {
+ out_row[0] = in[2];
+ out_row[1] = in[1];
+ out_row[2] = in[0];
+ out_row[3] = 255;
+ out_row += 4;
+ in += 3;
+
+ if( ++col == cols ) {
+ // run spans across rows
col = 0;
if( row > 0 )
row--;
else
- goto breakOut;
- pixbuf = ( uint32_t * )pixels + row * columns;
+ goto break_out;
+ out_row = out + row * cols * 4;
}
}
}
}
-breakOut: ;
-
}
- return qtrue;
-
+break_out:
+ return Q_ERR_SUCCESS;
}
TGA_DECODE( bgra_rle ) {
int col, row;
- uint32_t *pixbuf, color;
- byte packetHeader, packetSize;
+ byte *out_row;
+ uint32_t color;
+ unsigned packet_header, packet_size;
int j;
for( row = rows - 1; row >= 0; row-- ) {
- pixbuf = ( uint32_t * )pixels + row * columns;
+ out_row = out + row * cols * 4;
- for( col = 0; col < columns; ) {
- packetHeader = *data++;
- packetSize = 1 + ( packetHeader & 0x7f );
+ for( col = 0; col < cols; ) {
+ packet_header = *in++;
+ packet_size = 1 + ( packet_header & 0x7f );
- if( packetHeader & 0x80 ) {
- /* run-length packet */
- if( data + 4 > maxp ) {
- return qfalse;
+ if( packet_header & 0x80 ) {
+ // run-length packet
+ if( in + 4 > max_in ) {
+ return Q_ERR_BAD_RLE_PACKET;
}
- color = MakeColor( data[2], data[1], data[0], data[3] );
- data += 4;
- for( j = 0; j < packetSize; j++ ) {
- *pixbuf++ = color;
-
- col++;
- if( col == columns ) {
- /* run spans across rows */
+ color = MakeColor( in[2], in[1], in[0], in[3] );
+ in += 4;
+ for( j = 0; j < packet_size; j++ ) {
+ *(uint32_t *)out_row = color;
+ out_row += 4;
+
+ if( ++col == cols ) {
+ // run spans across rows
col = 0;
-
if( row > 0 )
row--;
else
- goto breakOut;
-
- pixbuf = ( uint32_t * )pixels + row * columns;
+ goto break_out;
+ out_row = out + row * cols * 4;
}
}
} else {
- /* non run-length packet */
- if( data + 4 * packetSize > maxp ) {
- return qfalse;
+ // non run-length packet
+ if( in + 4 * packet_size > max_in ) {
+ return Q_ERR_BAD_RLE_PACKET;
}
- for( j = 0; j < packetSize; j++ ) {
- *pixbuf++ = MakeColor( data[2], data[1], data[0], data[3] );
- data += 4;
-
- col++;
- if( col == columns ) {
- /* run spans across rows */
+ for( j = 0; j < packet_size; j++ ) {
+ out_row[0] = in[2];
+ out_row[1] = in[1];
+ out_row[2] = in[0];
+ out_row[3] = in[3];
+ out_row += 4;
+ in += 4;
+
+ if( ++col == cols ) {
+ // run spans across rows
col = 0;
if( row > 0 )
row--;
else
- goto breakOut;
- pixbuf = ( uint32_t * )pixels + row * columns;
+ goto break_out;
+ out_row = out + row * cols * 4;
}
}
}
}
-breakOut: ;
-
}
- return qtrue;
-
+break_out:
+ return Q_ERR_SUCCESS;
}
-#define TARGA_HEADER_SIZE 18
-
/*
=============
-LoadTGA
+IMG_LoadTGA
=============
*/
-void IMG_LoadTGA( const char *filename, byte **pic, int *width, int *height ) {
+qerror_t IMG_LoadTGA( const char *filename, byte **pic, int *width, int *height ) {
byte *buffer;
- size_t length;
+ size_t length, offset;
byte *pixels;
- int offset, w, h;
+ unsigned w, h, id_length, image_type, pixel_size, attributes, bpp;
tga_decode_t decode;
- int id_length, image_type, pixel_size, attributes, bpp;
+ qerror_t ret;
if( !filename || !pic ) {
Com_Error( ERR_FATAL, "LoadTGA: NULL" );
@@ -462,11 +456,11 @@ void IMG_LoadTGA( const char *filename, byte **pic, int *width, int *height ) {
//
length = FS_LoadFile( filename, ( void ** )&buffer );
if( !buffer ) {
- return;
+ return length;
}
if( length < TARGA_HEADER_SIZE ) {
- Com_WPrintf( "LoadTGA: %s: file too small\n", filename );
+ ret = Q_ERR_FILE_TOO_SMALL;
goto finish;
}
@@ -480,7 +474,7 @@ void IMG_LoadTGA( const char *filename, byte **pic, int *width, int *height ) {
// skip TARGA image comment
offset = TARGA_HEADER_SIZE + id_length;
if( offset + 4 > length ) {
- Com_WPrintf( "LoadTGA: %s: offset out of range\n", filename );
+ ret = Q_ERR_BAD_EXTENT;
goto finish;
}
@@ -489,21 +483,20 @@ void IMG_LoadTGA( const char *filename, byte **pic, int *width, int *height ) {
} else if( pixel_size == 24 ) {
bpp = 3;
} else {
- Com_WPrintf( "LoadTGA: %s: only 32 and 24 bit targa RGB "
- "images supported, this one is %d bit\n",
- filename, pixel_size );
+ Com_DPrintf( "%s: %s: only 32 and 24 bit targa RGB images supported\n", __func__, filename );
+ ret = Q_ERR_INVALID_FORMAT;
goto finish;
}
if( w < 1 || h < 1 || w > MAX_TEXTURE_SIZE || h > MAX_TEXTURE_SIZE ) {
- Com_WPrintf( "LoadTGA: %s: bad dimensions: %dx%d\n",
- filename, w, h );
+ Com_DPrintf( "%s: %s: invalid image dimensions\n", __func__, filename );
+ ret = Q_ERR_INVALID_FORMAT;
goto finish;
}
if( image_type == 2 ) {
if( offset + w * h * bpp > length ) {
- Com_WPrintf( "LoadTGA: %s: malformed targa image\n", filename );
+ ret = Q_ERR_BAD_EXTENT;
goto finish;
}
if( attributes & 32 ) {
@@ -521,8 +514,8 @@ void IMG_LoadTGA( const char *filename, byte **pic, int *width, int *height ) {
}
} else if( image_type == 10 ) {
if( attributes & 32 ) {
- Com_WPrintf( "LoadTGA: %s: vertically flipped, RLE encoded "
- "images are not supported\n", filename );
+ Com_DPrintf( "%s: %s: vertically flipped, RLE encoded images are not supported\n", __func__, filename );
+ ret = Q_ERR_INVALID_FORMAT;
goto finish;
}
if( pixel_size == 32 ) {
@@ -531,47 +524,37 @@ void IMG_LoadTGA( const char *filename, byte **pic, int *width, int *height ) {
decode = tga_decode_bgr_rle;
}
} else {
- Com_WPrintf( "LoadTGA: %s: only type 2 and 10 targa RGB "
- "images supported, this one is %d\n",
- filename, image_type );
+ Com_DPrintf( "%s: %s: only type 2 and 10 targa RGB images supported\n", __func__, filename );
+ ret = Q_ERR_INVALID_FORMAT;
goto finish;
}
pixels = IMG_AllocPixels( w * h * 4 );
- if( decode( buffer + offset, pixels, w, h, buffer + length ) ) {
- *pic = pixels;
- *width = w;
- *height = h;
- } else {
+ ret = decode( buffer + offset, pixels, w, h, buffer + length );
+ if( ret < 0 ) {
IMG_FreePixels( pixels );
+ goto finish;
}
+
+ *pic = pixels;
+ *width = w;
+ *height = h;
+
finish:
FS_FreeFile( buffer );
+ return ret;
}
/*
-=========================================================
-
-TARGA WRITING
-
-=========================================================
-*/
-
-/*
=================
-IMG_WriteTGA
+IMG_SaveTGA
=================
*/
-qboolean IMG_WriteTGA( const char *filename, const byte *bgr, int width, int height ) {
- int length;
- fileHandle_t f;
+qerror_t IMG_SaveTGA( qhandle_t f, const char *filename, const byte *bgr, int width, int height, int unused ) {
+ size_t len;
byte header[TARGA_HEADER_SIZE];
+ ssize_t ret;
- FS_FOpenFile( filename, &f, FS_MODE_WRITE );
- if( !f ) {
- return qfalse;
- }
-
memset( &header, 0, sizeof( header ) );
header[ 2] = 2; // uncompressed type
header[12] = width & 255;
@@ -580,21 +563,18 @@ qboolean IMG_WriteTGA( const char *filename, const byte *bgr, int width, int hei
header[15] = height >> 8;
header[16] = 24; // pixel size
- if( FS_Write( &header, sizeof( header ), f ) != sizeof( header ) ) {
- goto fail;
+ ret = FS_Write( &header, sizeof( header ), f );
+ if( ret < 0 ) {
+ return ret;
}
- length = width * height * 3;
- if( FS_Write( bgr, length, f ) != length ) {
- goto fail;
+ len = width * height * 3;
+ ret = FS_Write( bgr, len, f );
+ if( ret < 0 ) {
+ return ret;
}
-
- FS_FCloseFile( f );
- return qtrue;
-
-fail:
- FS_FCloseFile( f );
- return qfalse;
+
+ return Q_ERR_SUCCESS;
}
#endif // USE_TGA
@@ -602,7 +582,7 @@ fail:
/*
=========================================================
-JPEG LOADING
+JPEG IMAGES
=========================================================
*/
@@ -613,41 +593,43 @@ typedef struct my_error_mgr {
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
const char *filename;
+ qerror_t error;
} *my_error_ptr;
METHODDEF( void )my_output_message( j_common_ptr cinfo ) {
char buffer[JMSG_LENGTH_MAX];
- my_error_ptr myerr = ( my_error_ptr )cinfo->err;
+ my_error_ptr jerr = ( my_error_ptr )cinfo->err;
(*cinfo->err->format_message)( cinfo, buffer );
- Com_WPrintf( "LoadJPG: %s: %s\n", myerr->filename, buffer );
+ Com_EPrintf( "libjpeg: %s: %s\n", jerr->filename, buffer );
}
METHODDEF( void )my_error_exit( j_common_ptr cinfo ) {
- my_error_ptr myerr = ( my_error_ptr )cinfo->err;
+ my_error_ptr jerr = ( my_error_ptr )cinfo->err;
(*cinfo->err->output_message)( cinfo );
- longjmp( myerr->setjmp_buffer, 1 );
+ jerr->error = Q_ERR_LIBRARY_ERROR;
+ longjmp( jerr->setjmp_buffer, 1 );
}
-
METHODDEF( void )mem_init_source( j_decompress_ptr cinfo ) { }
METHODDEF( boolean )mem_fill_input_buffer( j_decompress_ptr cinfo ) {
my_error_ptr jerr = ( my_error_ptr )cinfo->err;
+ jerr->error = Q_ERR_FILE_TOO_SMALL;
longjmp( jerr->setjmp_buffer, 1 );
return TRUE;
}
-
METHODDEF( void )mem_skip_input_data( j_decompress_ptr cinfo, long num_bytes ) {
struct jpeg_source_mgr *src = cinfo->src;
my_error_ptr jerr = ( my_error_ptr )cinfo->err;
if( src->bytes_in_buffer < num_bytes ) {
+ jerr->error = Q_ERR_FILE_TOO_SMALL;
longjmp( jerr->setjmp_buffer, 1 );
}
@@ -657,8 +639,7 @@ METHODDEF( void )mem_skip_input_data( j_decompress_ptr cinfo, long num_bytes ) {
METHODDEF( void )mem_term_source( j_decompress_ptr cinfo ) { }
-
-METHODDEF( void )jpeg_mem_src( j_decompress_ptr cinfo, byte *data, size_t size ) {
+METHODDEF( void )my_mem_src( j_decompress_ptr cinfo, byte *data, size_t size ) {
cinfo->src = ( struct jpeg_source_mgr * )(*cinfo->mem->alloc_small)(
( j_common_ptr )cinfo, JPOOL_PERMANENT, sizeof( struct jpeg_source_mgr ) );
@@ -673,20 +654,20 @@ METHODDEF( void )jpeg_mem_src( j_decompress_ptr cinfo, byte *data, size_t size )
/*
=================
-LoadJPG
+IMG_LoadJPG
=================
*/
-void IMG_LoadJPG( const char *filename, byte **pic, int *width, int *height ) {
+qerror_t IMG_LoadJPG( const char *filename, byte **pic, int *width, int *height ) {
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
- JSAMPARRAY buffer;
- int row_stride;
+ JSAMPROW row_pointer;
+ byte buffer[MAX_TEXTURE_SIZE*3];
byte *rawdata;
size_t rawlength;
- byte *pixels;
- byte *src;
- uint32_t *dst;
+ byte *volatile pixels;
+ byte *in, *out;
int i;
+ qerror_t ret;
if( !filename || !pic ) {
Com_Error( ERR_FATAL, "LoadJPG: NULL" );
@@ -696,88 +677,102 @@ void IMG_LoadJPG( const char *filename, byte **pic, int *width, int *height ) {
rawlength = FS_LoadFile( filename, ( void ** )&rawdata );
if( !rawdata ) {
- return;
+ return rawlength;
}
cinfo.err = jpeg_std_error( &jerr.pub );
jerr.pub.error_exit = my_error_exit;
jerr.pub.output_message = my_output_message;
jerr.filename = filename;
+ jerr.error = Q_ERR_FAILURE;
jpeg_create_decompress( &cinfo );
-
+
if( setjmp( jerr.setjmp_buffer ) ) {
- jpeg_destroy_decompress( &cinfo );
- if( pixels ) {
- IMG_FreePixels( pixels );
- }
- FS_FreeFile( rawdata );
- return;
+ IMG_FreePixels( pixels );
+ ret = jerr.error;
+ goto fail;
}
- jpeg_mem_src( &cinfo, rawdata, rawlength );
+ my_mem_src( &cinfo, rawdata, rawlength );
jpeg_read_header( &cinfo, TRUE );
- jpeg_start_decompress( &cinfo );
- if( cinfo.output_components != 3 /*&& cinfo.output_components != 4*/ ) {
- Com_WPrintf( "LoadJPG: %s: unsupported number of color components: %i\n",
- filename, cinfo.output_components );
- jpeg_destroy_decompress( &cinfo );
- FS_FreeFile( rawdata );
- return;
+ if( cinfo.jpeg_color_space != JCS_RGB && cinfo.jpeg_color_space != JCS_GRAYSCALE ) {
+ Com_DPrintf( "%s: %s: invalid image color space\n", __func__, filename );
+ ret = Q_ERR_INVALID_FORMAT;
+ goto fail;
}
- *width = cinfo.output_width;
- *height = cinfo.output_height;
+ jpeg_start_decompress( &cinfo );
+
+ if( cinfo.output_components != 3 && cinfo.output_components != 1 ) {
+ Com_DPrintf( "%s: %s: invalid number of color components\n", __func__, filename );
+ ret = Q_ERR_INVALID_FORMAT;
+ goto fail;
+ }
- pixels = IMG_AllocPixels( cinfo.output_width * cinfo.output_height * 4 );
+ if( cinfo.output_width > MAX_TEXTURE_SIZE || cinfo.output_height > MAX_TEXTURE_SIZE ) {
+ Com_DPrintf( "%s: %s: invalid image dimensions\n", __func__, filename );
+ ret = Q_ERR_INVALID_FORMAT;
+ goto fail;
+ }
- row_stride = cinfo.output_width * cinfo.output_components;
+ pixels = out = IMG_AllocPixels( cinfo.output_height * cinfo.output_width * 4 );
+ row_pointer = ( JSAMPROW )buffer;
- buffer = (*cinfo.mem->alloc_sarray)( ( j_common_ptr )&cinfo, JPOOL_IMAGE, row_stride, 1 );
+ if( cinfo.output_components == 3 ) {
+ while( cinfo.output_scanline < cinfo.output_height ) {
+ jpeg_read_scanlines( &cinfo, &row_pointer, 1 );
- dst = ( uint32_t * )pixels;
- while( cinfo.output_scanline < cinfo.output_height ) {
- jpeg_read_scanlines( &cinfo, buffer, 1 );
+ in = buffer;
+ for( i = 0; i < cinfo.output_width; i++, out += 4, in += 3 ) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = 255;
+ }
+ }
+ } else {
+ while( cinfo.output_scanline < cinfo.output_height ) {
+ jpeg_read_scanlines( &cinfo, &row_pointer, 1 );
- src = ( byte * )buffer[0];
- for( i = 0; i < cinfo.output_width; i++, src += 3 ) {
- *dst++ = MakeColor( src[0], src[1], src[2], 255 );
+ in = buffer;
+ for( i = 0; i < cinfo.output_width; i++, out += 4, in += 1 ) {
+ out[0] = out[1] = out[2] = in[0];
+ out[3] = 255;
+ }
}
}
- jpeg_finish_decompress( &cinfo );
- jpeg_destroy_decompress( &cinfo );
+ *width = cinfo.output_width;
+ *height = cinfo.output_height;
- FS_FreeFile( rawdata );
+ jpeg_finish_decompress( &cinfo );
*pic = pixels;
+ ret = Q_ERR_SUCCESS;
+fail:
+ jpeg_destroy_decompress( &cinfo );
+ FS_FreeFile( rawdata );
+ return ret;
}
-/*
-=========================================================
-
-JPEG WRITING
-
-=========================================================
-*/
-
-#define OUTPUT_BUF_SIZE 4096
+#define OUTPUT_BUF_SIZE 0x10000 // 64 KiB
typedef struct my_destination_mgr {
- struct jpeg_destination_mgr pub; /* public fields */
+ struct jpeg_destination_mgr pub;
- fileHandle_t hFile; /* target stream */
- JOCTET *buffer; /* start of buffer */
+ qhandle_t f;
+ JOCTET *buffer;
} *my_dest_ptr;
-
METHODDEF( void ) vfs_init_destination( j_compress_ptr cinfo ) {
my_dest_ptr dest = ( my_dest_ptr )cinfo->dest;
- /* Allocate the output buffer --- it will be released when done with image */
- dest->buffer = ( JOCTET * )(*cinfo->mem->alloc_small)( ( j_common_ptr )cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * sizeof( JOCTET ) );
+ // Allocate the output buffer --- it will be released when done with image
+ dest->buffer = ( JOCTET * )(*cinfo->mem->alloc_small)
+ ( ( j_common_ptr )cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * sizeof( JOCTET ) );
dest->pub.next_output_byte = dest->buffer;
dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
@@ -786,8 +781,11 @@ METHODDEF( void ) vfs_init_destination( j_compress_ptr cinfo ) {
METHODDEF( boolean ) vfs_empty_output_buffer( j_compress_ptr cinfo ) {
my_dest_ptr dest = ( my_dest_ptr )cinfo->dest;
my_error_ptr jerr = ( my_error_ptr )cinfo->err;
+ ssize_t ret;
- if( FS_Write( dest->buffer, OUTPUT_BUF_SIZE, dest->hFile ) != OUTPUT_BUF_SIZE ) {
+ ret = FS_Write( dest->buffer, OUTPUT_BUF_SIZE, dest->f );
+ if( ret != OUTPUT_BUF_SIZE ) {
+ jerr->error = ret < 0 ? ret : Q_ERR_FAILURE;
longjmp( jerr->setjmp_buffer, 1 );
}
@@ -795,97 +793,96 @@ METHODDEF( boolean ) vfs_empty_output_buffer( j_compress_ptr cinfo ) {
dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
return TRUE;
-
}
METHODDEF( void ) vfs_term_destination( j_compress_ptr cinfo ) {
my_dest_ptr dest = ( my_dest_ptr )cinfo->dest;
my_error_ptr jerr = ( my_error_ptr )cinfo->err;
- int remaining = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
+ size_t remaining = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
+ ssize_t ret;
- /* Write any data remaining in the buffer */
+ // Write any data remaining in the buffer
if( remaining > 0 ) {
- if( FS_Write( dest->buffer, remaining, dest->hFile ) != remaining ) {
+ ret = FS_Write( dest->buffer, remaining, dest->f );
+ if( ret != remaining ) {
+ jerr->error = ret < 0 ? ret : Q_ERR_FAILURE;
longjmp( jerr->setjmp_buffer, 1 );
}
}
-
}
-
-METHODDEF( void ) jpeg_vfs_dst( j_compress_ptr cinfo, fileHandle_t hFile ) {
+METHODDEF( void ) my_vfs_dst( j_compress_ptr cinfo, qhandle_t f ) {
my_dest_ptr dest;
- dest = ( my_dest_ptr )(*cinfo->mem->alloc_small)( ( j_common_ptr )cinfo, JPOOL_PERMANENT, sizeof( struct my_destination_mgr ) );
+ dest = ( my_dest_ptr )(*cinfo->mem->alloc_small)
+ ( ( j_common_ptr )cinfo, JPOOL_PERMANENT, sizeof( struct my_destination_mgr ) );
cinfo->dest = &dest->pub;
dest->pub.init_destination = vfs_init_destination;
dest->pub.empty_output_buffer = vfs_empty_output_buffer;
dest->pub.term_destination = vfs_term_destination;
- dest->hFile = hFile;
-
+ dest->f = f;
}
/*
=================
-IMG_WriteJPG
+IMG_SaveJPG
=================
*/
-qboolean IMG_WriteJPG( const char *filename, const byte *rgb, int width, int height, int quality ) {
+qerror_t IMG_SaveJPG( qhandle_t f, const char *filename, const byte *rgb, int width, int height, int quality ) {
struct jpeg_compress_struct cinfo;
struct my_error_mgr jerr;
- fileHandle_t hFile;
- JSAMPROW row_pointer[1];
+ volatile JSAMPARRAY row_pointers;
int row_stride;
-
- FS_FOpenFile( filename, &hFile, FS_MODE_WRITE );
- if( !hFile ) {
- Com_DPrintf( "WriteJPG: %s: couldn't create file\n", filename );
- return qfalse;
- }
+ qerror_t ret;
+ int i;
cinfo.err = jpeg_std_error( &jerr.pub );
jerr.pub.error_exit = my_error_exit;
+ jerr.filename = filename;
+ jerr.error = Q_ERR_FAILURE;
+
+ row_pointers = NULL;
if( setjmp( jerr.setjmp_buffer ) ) {
- Com_DPrintf( "WriteJPG: %s: JPEGLIB signaled an error\n", filename );
- jpeg_destroy_compress( &cinfo );
- FS_FCloseFile( hFile );
- return qfalse;
+ ret = jerr.error;
+ goto fail;
}
jpeg_create_compress( &cinfo );
- jpeg_vfs_dst( &cinfo, hFile );
+ my_vfs_dst( &cinfo, f );
- cinfo.image_width = width; // image width and height, in pixels
+ cinfo.image_width = width; // image width and height, in pixels
cinfo.image_height = height;
- cinfo.input_components = 3; // # of color components per pixel
- cinfo.in_color_space = JCS_RGB; // colorspace of input image
-
- clamp( quality, 0, 100 );
+ cinfo.input_components = 3; // # of color components per pixel
+ cinfo.in_color_space = JCS_RGB; // colorspace of input image
jpeg_set_defaults( &cinfo );
- jpeg_set_quality( &cinfo, quality, TRUE );
+ jpeg_set_quality( &cinfo, clamp( quality, 0, 100 ), TRUE );
jpeg_start_compress( &cinfo, TRUE );
+ row_pointers = FS_AllocTempMem( sizeof( JSAMPROW ) * height );
row_stride = width * 3; // JSAMPLEs per row in image_buffer
- while( cinfo.next_scanline < cinfo.image_height ) {
- row_pointer[0] = ( byte * )( &rgb[( cinfo.image_height - cinfo.next_scanline - 1 ) * row_stride] );
- jpeg_write_scanlines( &cinfo, row_pointer, 1 );
+ for( i = 0; i < height; i++ ) {
+ row_pointers[i] = ( JSAMPROW )( rgb + ( height - i - 1 ) * row_stride );
}
+ jpeg_write_scanlines( &cinfo, row_pointers, height );
+
jpeg_finish_compress( &cinfo );
- FS_FCloseFile( hFile );
- jpeg_destroy_compress( &cinfo );
+ ret = Q_ERR_SUCCESS;
- return qtrue;
+fail:
+ FS_FreeFile( row_pointers );
+ jpeg_destroy_compress( &cinfo );
+ return ret;
}
-#endif /* USE_JPG */
+#endif // USE_JPG
#if USE_PNG
@@ -893,55 +890,67 @@ qboolean IMG_WriteJPG( const char *filename, const byte *rgb, int width, int hei
/*
=========================================================
-PNG LOADING
+PNG IMAGES
=========================================================
*/
-struct pngReadStruct {
- byte *data;
- byte *maxp;
-};
+typedef struct {
+ png_bytep next_in;
+ png_size_t avail_in;
+} my_png_io;
-static void QDECL png_vfs_read_fn( png_structp png_ptr, png_bytep buf, png_size_t size ) {
- struct pngReadStruct *r = png_get_io_ptr( png_ptr );
+typedef struct {
+ png_const_charp filename;
+ qerror_t error;
+} my_png_error;
- if( r->data + size > r->maxp ) {
+static void my_png_read_fn( png_structp png_ptr, png_bytep buf, png_size_t size ) {
+ my_png_io *io = png_get_io_ptr( png_ptr );
+
+ if( size > io->avail_in ) {
+ my_png_error *err = png_get_error_ptr( png_ptr );
+ err->error = Q_ERR_FILE_TOO_SMALL;
png_error( png_ptr, "read error" );
} else {
- memcpy( buf, r->data, size );
- r->data += size;
+ memcpy( buf, io->next_in, size );
+ io->next_in += size;
+ io->avail_in -= size;
}
}
-static void QDECL png_console_error_fn( png_structp png_ptr, png_const_charp error_msg ) {
- char *f = png_get_error_ptr( png_ptr );
+static void my_png_error_fn( png_structp png_ptr, png_const_charp error_msg ) {
+ my_png_error *err = png_get_error_ptr( png_ptr );
- Com_EPrintf( "LoadPNG: %s: %s\n", f, error_msg );
+ if( err->error == Q_ERR_LIBRARY_ERROR ) {
+ Com_EPrintf( "libpng: %s: %s\n", err->filename, error_msg );
+ }
longjmp( png_jmpbuf( png_ptr ), -1 );
}
-static void QDECL png_console_warning_fn( png_structp png_ptr, png_const_charp warning_msg ) {
- char *f = png_get_error_ptr( png_ptr );
+static void my_png_warning_fn( png_structp png_ptr, png_const_charp warning_msg ) {
+ my_png_error *err = png_get_error_ptr( png_ptr );
- Com_WPrintf( "LoadPNG: %s: %s\n", f, warning_msg );
+ Com_WPrintf( "libpng: %s: %s\n", err->filename, warning_msg );
}
/*
=================
-LoadPNG
+IMG_LoadPNG
=================
*/
-void IMG_LoadPNG( const char *filename, byte **pic, int *width, int *height ) {
+qerror_t IMG_LoadPNG( const char *filename, byte **pic, int *width, int *height ) {
byte *rawdata;
size_t rawlength;
- byte *pixels;
+ byte *volatile pixels;
png_bytep row_pointers[MAX_TEXTURE_SIZE];
png_uint_32 w, h, rowbytes, row;
int bitdepth, colortype;
png_structp png_ptr;
png_infop info_ptr;
- struct pngReadStruct r;
+ my_png_io my_io;
+ my_png_error my_err;
+ qerror_t ret;
if( !filename || !pic ) {
Com_Error( ERR_FATAL, "LoadPNG: NULL" );
@@ -951,47 +960,45 @@ void IMG_LoadPNG( const char *filename, byte **pic, int *width, int *height ) {
rawlength = FS_LoadFile( filename, ( void ** )&rawdata );
if( !rawdata ) {
- return;
+ return rawlength;
}
+ ret = Q_ERR_LIBRARY_ERROR;
+
+ my_err.filename = filename;
+ my_err.error = Q_ERR_LIBRARY_ERROR;
+
png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
- ( png_voidp )filename, png_console_error_fn, png_console_warning_fn );
+ ( png_voidp )&my_err, my_png_error_fn, my_png_warning_fn );
if( !png_ptr ) {
- goto fail;
+ goto fail1;
}
info_ptr = png_create_info_struct( png_ptr );
if( !info_ptr ) {
- png_destroy_read_struct( &png_ptr, NULL, NULL );
- goto fail;
+ goto fail2;
}
if( setjmp( png_jmpbuf( png_ptr ) ) ) {
- png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
- if( pixels ) {
- IMG_FreePixels( pixels );
- }
- goto fail;
+ IMG_FreePixels( pixels );
+ ret = my_err.error;
+ goto fail2;
}
- r.data = rawdata;
- r.maxp = rawdata + rawlength;
- png_set_read_fn( png_ptr, ( png_voidp )&r, png_vfs_read_fn );
+ my_io.next_in = rawdata;
+ my_io.avail_in = rawlength;
+ png_set_read_fn( png_ptr, ( png_voidp )&my_io, my_png_read_fn );
png_read_info( png_ptr, info_ptr );
- if( !png_get_IHDR( png_ptr, info_ptr, &w, &h, &bitdepth, &colortype,
- NULL, NULL, NULL ) )
- {
- png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
- goto fail;
+ if( !png_get_IHDR( png_ptr, info_ptr, &w, &h, &bitdepth, &colortype, NULL, NULL, NULL ) ) {
+ goto fail2;
}
if( w > MAX_TEXTURE_SIZE || h > MAX_TEXTURE_SIZE ) {
- Com_EPrintf( "LoadPNG: %s: oversize image dimensions: %lux%lu\n",
- filename, w, h );
- png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
- goto fail;
+ Com_DPrintf( "%s: %s: invalid image dimensions\n", __func__, filename );
+ ret = Q_ERR_INVALID_FORMAT;
+ goto fail2;
}
switch( colortype ) {
@@ -1033,67 +1040,74 @@ void IMG_LoadPNG( const char *filename, byte **pic, int *width, int *height ) {
png_read_end( png_ptr, info_ptr );
- png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
-
*pic = pixels;
*width = w;
*height = h;
+ ret = Q_ERR_SUCCESS;
-fail:
+fail2:
+ png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
+fail1:
FS_FreeFile( rawdata );
+ return ret;
}
-static void QDECL png_vfs_write_fn( png_structp png_ptr, png_bytep buf, png_size_t size ) {
- fileHandle_t *f = png_get_io_ptr( png_ptr );
- FS_Write( buf, size, *f );
-}
+static void my_png_write_fn( png_structp png_ptr, png_bytep buf, png_size_t size ) {
+ qhandle_t *f = png_get_io_ptr( png_ptr );
+ ssize_t ret = FS_Write( buf, size, *f );
-static void QDECL png_vfs_flush_fn( png_structp png_ptr ) {
- //fileHandle_t *f = png_get_io_ptr( png_ptr );
- //FS_Flush( *f );
+ if( ret != size ) {
+ my_png_error *err = png_get_error_ptr( png_ptr );
+ err->error = ret < 0 ? ret : Q_ERR_FAILURE;
+ png_error( png_ptr, "write error" );
+ }
}
-qboolean IMG_WritePNG( const char *filename, const byte *rgb, int width, int height, int compression ) {
+static void my_png_flush_fn( png_structp png_ptr ) { }
+
+/*
+=================
+IMG_SavePNG
+=================
+*/
+qerror_t IMG_SavePNG( qhandle_t f, const char *filename, const byte *rgb, int width, int height, int compression ) {
png_structp png_ptr;
png_infop info_ptr;
- fileHandle_t f;
- qboolean ret = qfalse;
- png_bytepp row_pointers = NULL;
- int row_stride;
- int i;
+ volatile png_bytepp row_pointers;
+ int i, row_stride;
+ my_png_error my_err;
+ qerror_t ret;
- FS_FOpenFile( filename, &f, FS_MODE_WRITE );
- if( !f ) {
- Com_DPrintf( "WritePNG: %s: couldn't create file\n", filename );
- return qfalse;
- }
+ row_pointers = NULL;
+ ret = Q_ERR_LIBRARY_ERROR;
+
+ my_err.filename = filename;
+ my_err.error = Q_ERR_LIBRARY_ERROR;
png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING,
- ( png_voidp )filename, png_console_error_fn, png_console_warning_fn );
+ ( png_voidp )&my_err, my_png_error_fn, my_png_warning_fn );
if( !png_ptr ) {
- goto fail;
+ goto fail1;
}
info_ptr = png_create_info_struct( png_ptr );
if( !info_ptr ) {
- png_destroy_write_struct( &png_ptr, NULL );
- goto fail;
+ goto fail2;
}
if( setjmp( png_jmpbuf( png_ptr ) ) ) {
- png_destroy_write_struct( &png_ptr, &info_ptr );
- goto fail;
+ ret = my_err.error;
+ goto fail3;
}
png_set_write_fn( png_ptr, ( png_voidp )&f,
- png_vfs_write_fn, png_vfs_flush_fn );
+ my_png_write_fn, my_png_flush_fn );
png_set_IHDR( png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,
- PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
- PNG_FILTER_TYPE_DEFAULT );
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT );
- clamp( compression, Z_NO_COMPRESSION, Z_BEST_COMPRESSION );
- png_set_compression_level( png_ptr, compression );
+ png_set_compression_level( png_ptr,
+ clamp( compression, Z_NO_COMPRESSION, Z_BEST_COMPRESSION ) );
row_pointers = FS_AllocTempMem( sizeof( png_bytep ) * height );
row_stride = width * 3;
@@ -1105,19 +1119,17 @@ qboolean IMG_WritePNG( const char *filename, const byte *rgb, int width, int hei
png_write_png( png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL );
- png_destroy_write_struct( &png_ptr, &info_ptr );
-
- ret = qtrue;
+ ret = Q_ERR_SUCCESS;
-fail:
- if( row_pointers ) {
- FS_FreeFile( row_pointers );
- }
- FS_FCloseFile( f );
+fail3:
+ FS_FreeFile( row_pointers );
+fail2:
+ png_destroy_write_struct( &png_ptr, &info_ptr );
+fail1:
return ret;
}
-#endif /* USE_PNG */
+#endif // USE_PNG
/*
=========================================================
@@ -1129,7 +1141,6 @@ IMAGE MANAGER
#define RIMAGES_HASH 256
-
image_t r_images[MAX_RIMAGES];
list_t r_imageHash[RIMAGES_HASH];
int r_numImages;
@@ -1147,6 +1158,7 @@ IMG_List_f
===============
*/
static void IMG_List_f( void ) {
+ static const char types[8] = "MSWPYC?";
int i;
image_t *image;
int texels, count;
@@ -1157,36 +1169,15 @@ static void IMG_List_f( void ) {
for( i = 0, image = r_images; i < r_numImages; i++, image++ ) {
if( !image->registration_sequence )
continue;
- texels += image->upload_width * image->upload_height;
- switch( image->type ) {
- case it_skin:
- Com_Printf( "M" );
- break;
- case it_sprite:
- Com_Printf( "S" );
- break;
- case it_wall:
- Com_Printf( "W" );
- break;
- case it_pic:
- Com_Printf( "P" );
- break;
- case it_sky:
- Com_Printf( "Y" );
- break;
- case it_charset:
- Com_Printf( "C" );
- break;
- default:
- Com_Printf( " " );
- break;
- }
- Com_Printf( " %4i %4i %s: %s\n",
+ Com_Printf( "%c %4i %4i %s: %s\n",
+ types[image->type],
image->upload_width,
image->upload_height,
( image->flags & if_paletted ) ? "PAL" : "RGB",
image->name );
+
+ texels += image->upload_width * image->upload_height;
count++;
}
Com_Printf( "Total images: %d (out of %d slots)\n", count, r_numImages );
@@ -1267,48 +1258,52 @@ IMG_Find
Finds or loads the given image, adding it to the hash table.
===============
*/
-image_t *IMG_Find( const char *name, imagetype_t type ) {
+static qerror_t _IMG_Find( const char *name, imagetype_t type, image_t **image_p ) {
image_t *image;
byte *pic;
int width, height;
char buffer[MAX_QPATH];
char *ext;
- size_t length;
+ size_t len;
unsigned hash, extHash;
imageflags_t flags;
#if USE_PNG || USE_JPG || USE_TGA
char *s;
#endif
+ qerror_t err;
+
+ *image_p = NULL;
if( !name ) {
Com_Error( ERR_FATAL, "%s: NULL", __func__ );
}
- length = strlen( name );
- if( length >= MAX_QPATH ) {
+ len = strlen( name );
+ if( len >= MAX_QPATH ) {
Com_Error( ERR_FATAL, "%s: oversize name", __func__ );
}
- if( length <= 4 ) {
- return NULL; // must have at least 1 char of base name
+ if( len <= 4 ) {
+ return Q_ERR_INVALID_PATH; // must have at least 1 char of base name
}
- length -= 4;
- if( name[length] != '.' ) {
- return NULL;
+ len -= 4;
+ if( name[len] != '.' ) {
+ return Q_ERR_INVALID_PATH;
}
strcpy( buffer, name );
- buffer[length] = 0;
+ buffer[len] = 0;
hash = Com_HashPath( buffer, RIMAGES_HASH );
- if( ( image = IMG_Lookup( buffer, type, hash, length ) ) != NULL ) {
+ if( ( image = IMG_Lookup( buffer, type, hash, len ) ) != NULL ) {
image->registration_sequence = registration_sequence;
- return image;
+ *image_p = image;
+ return Q_ERR_SUCCESS;
}
- ext = buffer + length;
+ ext = buffer + len;
Q_strlwr( ext + 1 );
extHash = MakeRawLong( '.', ext[1], ext[2], ext[3] );
@@ -1325,22 +1320,24 @@ image_t *IMG_Find( const char *name, imagetype_t type ) {
#if USE_PNG
case 'p': // try *.png
strcpy( ext, ".png" );
- IMG_LoadPNG( buffer, &pic, &width, &height );
+ err = IMG_LoadPNG( buffer, &pic, &width, &height );
break;
#endif
#if USE_JPG
case 'j': // try *.jpg
strcpy( ext, ".jpg" );
- IMG_LoadJPG( buffer, &pic, &width, &height );
+ err = IMG_LoadJPG( buffer, &pic, &width, &height );
break;
#endif
#if USE_TGA
case 't': // try *.tga
strcpy( ext, ".tga" );
- IMG_LoadTGA( buffer, &pic, &width, &height );
+ err = IMG_LoadTGA( buffer, &pic, &width, &height );
break;
- }
#endif
+ default:
+ continue;
+ }
if( pic ) {
// replacing 8 bit texture with 32 bit texture
if( extHash == EXTENSION_WAL ) {
@@ -1350,28 +1347,27 @@ image_t *IMG_Find( const char *name, imagetype_t type ) {
}
goto create;
}
+ if( err != Q_ERR_NOENT ) {
+ return err;
+ }
}
- switch( extHash ) {
- case EXTENSION_PNG:
- case EXTENSION_TGA:
- case EXTENSION_JPG:
- case EXTENSION_PCX:
+ if( extHash == EXTENSION_WAL ) {
+ strcpy( ext, ".wal" );
+ if( ( image = IMG_LoadWAL( buffer ) ) != NULL ) {
+ goto append;
+ }
+ err = Q_ERR_NOENT;
+ } else {
strcpy( ext, ".pcx" );
- IMG_LoadPCX( buffer, &pic, NULL, &width, &height );
+ err = IMG_LoadPCX( buffer, &pic, NULL, &width, &height );
if( pic ) {
flags |= if_paletted;
goto create;
}
- return NULL;
- case EXTENSION_WAL:
- strcpy( ext, ".wal" );
- if( ( image = IMG_LoadWAL( buffer ) ) != NULL ) {
- goto append;
- }
}
- return NULL;
+ return err;
}
#endif
@@ -1380,10 +1376,13 @@ image_t *IMG_Find( const char *name, imagetype_t type ) {
#if USE_PNG
// try *.png
strcpy( ext, ".png" );
- IMG_LoadPNG( buffer, &pic, &width, &height );
+ err = IMG_LoadPNG( buffer, &pic, &width, &height );
if( pic ) {
goto create;
}
+ if( err != Q_ERR_NOENT ) {
+ return err;
+ }
#endif
#if USE_JPG || USE_TGA
for( s = r_texture_formats->string; *s; s++ ) {
@@ -1391,37 +1390,45 @@ image_t *IMG_Find( const char *name, imagetype_t type ) {
#if USE_JPG
case 'j': // try *.jpg
strcpy( ext, ".jpg" );
- IMG_LoadJPG( buffer, &pic, &width, &height );
+ err = IMG_LoadJPG( buffer, &pic, &width, &height );
break;
#endif
#if USE_TGA
case 't': // try *.tga
strcpy( ext, ".tga" );
- IMG_LoadTGA( buffer, &pic, &width, &height );
+ err = IMG_LoadTGA( buffer, &pic, &width, &height );
break;
- }
#endif
+ default:
+ continue;
+ }
if( pic ) {
goto create;
}
+ if( err != Q_ERR_NOENT ) {
+ return err;
+ }
}
#endif
// try *.pcx
strcpy( ext, ".pcx" );
- IMG_LoadPCX( buffer, &pic, NULL, &width, &height );
+ err = IMG_LoadPCX( buffer, &pic, NULL, &width, &height );
if( pic ) {
flags |= if_paletted;
goto create;
}
- return NULL;
+ return err;
case EXTENSION_TGA:
#if USE_TGA
strcpy( ext, ".tga" );
- IMG_LoadTGA( buffer, &pic, &width, &height );
+ err = IMG_LoadTGA( buffer, &pic, &width, &height );
if( pic ) {
goto create;
}
+ if( err != Q_ERR_NOENT ) {
+ return err;
+ }
#endif
#if USE_PNG || USE_JPG
@@ -1430,37 +1437,45 @@ image_t *IMG_Find( const char *name, imagetype_t type ) {
#if USE_PNG
case 'p': // try *.png
strcpy( ext, ".png" );
- IMG_LoadPNG( buffer, &pic, &width, &height );
+ err = IMG_LoadPNG( buffer, &pic, &width, &height );
break;
#endif
#if USE_JPG
case 'j': // try *.jpg
strcpy( ext, ".jpg" );
- IMG_LoadJPG( buffer, &pic, &width, &height );
+ err = IMG_LoadJPG( buffer, &pic, &width, &height );
break;
#endif
+ default:
+ continue;
}
if( pic ) {
goto create;
}
+ if( err != Q_ERR_NOENT ) {
+ return err;
+ }
}
#endif
// try *.pcx
strcpy( ext, ".pcx" );
- IMG_LoadPCX( buffer, &pic, NULL, &width, &height );
+ err = IMG_LoadPCX( buffer, &pic, NULL, &width, &height );
if( pic ) {
flags |= if_paletted;
goto create;
}
- return NULL;
+ return err;
case EXTENSION_JPG:
#if USE_JPG
strcpy( ext, ".jpg" );
- IMG_LoadJPG( buffer, &pic, &width, &height );
+ err = IMG_LoadJPG( buffer, &pic, &width, &height );
if( pic ) {
goto create;
}
+ if( err != Q_ERR_NOENT ) {
+ return err;
+ }
#endif
#if USE_PNG || USE_TGA
@@ -1469,39 +1484,47 @@ image_t *IMG_Find( const char *name, imagetype_t type ) {
#if USE_PNG
case 'p': // try *.png
strcpy( ext, ".png" );
- IMG_LoadPNG( buffer, &pic, &width, &height );
+ err = IMG_LoadPNG( buffer, &pic, &width, &height );
break;
#endif
#if USE_TGA
case 't': // try *.tga
strcpy( ext, ".tga" );
- IMG_LoadTGA( buffer, &pic, &width, &height );
+ err = IMG_LoadTGA( buffer, &pic, &width, &height );
break;
- }
#endif
+ default:
+ continue;
+ }
if( pic ) {
goto create;
}
+ if( err != Q_ERR_NOENT ) {
+ return err;
+ }
}
#endif
// try *.pcx
strcpy( ext, ".pcx" );
- IMG_LoadPCX( buffer, &pic, NULL, &width, &height );
+ err = IMG_LoadPCX( buffer, &pic, NULL, &width, &height );
if( pic ) {
flags |= if_paletted;
goto create;
}
- return NULL;
+ return err;
case EXTENSION_PCX:
strcpy( ext, ".pcx" );
- IMG_LoadPCX( buffer, &pic, NULL, &width, &height );
+ err = IMG_LoadPCX( buffer, &pic, NULL, &width, &height );
if( pic ) {
flags |= if_paletted;
goto create;
}
+ if( err != Q_ERR_NOENT ) {
+ return err;
+ }
#if USE_PNG || USE_JPG || USE_TGA
for( s = r_texture_formats->string; *s; s++ ) {
@@ -1509,28 +1532,33 @@ image_t *IMG_Find( const char *name, imagetype_t type ) {
#if USE_PNG
case 'p': // try *.png
strcpy( ext, ".png" );
- IMG_LoadPNG( buffer, &pic, &width, &height );
+ err = IMG_LoadPNG( buffer, &pic, &width, &height );
break;
#endif
#if USE_JPG
case 'j': // try *.jpg
strcpy( ext, ".jpg" );
- IMG_LoadJPG( buffer, &pic, &width, &height );
+ err = IMG_LoadJPG( buffer, &pic, &width, &height );
break;
#endif
#if USE_TGA
case 't': // try *.tga
strcpy( ext, ".tga" );
- IMG_LoadTGA( buffer, &pic, &width, &height );
+ err = IMG_LoadTGA( buffer, &pic, &width, &height );
break;
- }
#endif
+ default:
+ continue;
+ }
if( pic ) {
goto create;
}
+ if( err != Q_ERR_NOENT ) {
+ return err;
+ }
}
#endif
- return NULL;
+ return Q_ERR_NOENT;
case EXTENSION_WAL:
strcpy( ext, ".wal" );
@@ -1545,38 +1573,61 @@ image_t *IMG_Find( const char *name, imagetype_t type ) {
#if USE_PNG
case 'p': // try *.png
strcpy( ext, ".png" );
- IMG_LoadPNG( buffer, &pic, &width, &height );
+ err = IMG_LoadPNG( buffer, &pic, &width, &height );
break;
#endif
#if USE_JPG
case 'j': // try *.jpg
strcpy( ext, ".jpg" );
- IMG_LoadJPG( buffer, &pic, &width, &height );
+ err = IMG_LoadJPG( buffer, &pic, &width, &height );
break;
#endif
#if USE_TGA
case 't': // try *.tga
strcpy( ext, ".tga" );
- IMG_LoadTGA( buffer, &pic, &width, &height );
+ err = IMG_LoadTGA( buffer, &pic, &width, &height );
break;
- }
#endif
+ default:
+ continue;
+ }
if( pic ) {
goto create;
}
+ if( err != Q_ERR_NOENT ) {
+ return err;
+ }
}
#endif
- return NULL;
+ return Q_ERR_NOENT;
default:
- return NULL;
+ return Q_ERR_INVALID_PATH;
}
create:
image = IMG_Create( buffer, pic, width, height, type, flags );
append:
List_Append( &r_imageHash[hash], &image->entry );
- return image;
+ *image_p = image;
+ return Q_ERR_SUCCESS;
+}
+
+image_t *IMG_Find( const char *name, imagetype_t type ) {
+ image_t *image;
+ qerror_t ret;
+
+ ret = _IMG_Find( name, type, &image );
+ if( image ) {
+ return image;
+ }
+
+ // don't spam about missing images
+ if( ret != Q_ERR_NOENT ) {
+ Com_EPrintf( "Couldn't load %s: %s\n", name, Q_ErrorString( ret ) );
+ }
+
+ return NULL;
}
/*
@@ -1611,62 +1662,81 @@ qhandle_t R_RegisterSkin( const char *name ) {
return ( image - r_images );
}
-/*
-================
-R_RegisterPic
-================
-*/
-qhandle_t R_RegisterPic( const char *name ) {
+static qerror_t _register_image( const char *name, imagetype_t type, qhandle_t *handle ) {
image_t *image;
char fullname[MAX_QPATH];
+ size_t len;
+ qerror_t ret;
+
+ *handle = 0;
if( !r_numImages ) {
- return 0;
+ return Q_ERR_AGAIN;
}
- if( name[0] == '*' ) {
- image = IMG_Find( name + 1, it_tmp );
- } else if( name[0] == '/' || name[0] == '\\' ) {
- image = IMG_Find( name + 1, it_pic );
+ if( name[0] == '/' || name[0] == '\\' ) {
+ ret = _IMG_Find( name + 1, type, &image );
} else {
- Q_concat( fullname, sizeof( fullname ), "pics/", name, NULL );
- COM_DefaultExtension( fullname, ".pcx", sizeof( fullname ) );
- image = IMG_Find( fullname, it_pic );
+ len = Q_concat( fullname, sizeof( fullname ), "pics/", name, NULL );
+ if( len >= sizeof( fullname ) ) {
+ return Q_ERR_NAMETOOLONG;
+ }
+ len = COM_DefaultExtension( fullname, ".pcx", sizeof( fullname ) );
+ if( len >= sizeof( fullname ) ) {
+ return Q_ERR_NAMETOOLONG;
+ }
+ ret = _IMG_Find( fullname, type, &image );
}
if( !image ) {
- return 0;
+ return ret;
}
- return ( image - r_images );
+ *handle = ( image - r_images );
+ return Q_ERR_SUCCESS;
+}
+
+static qhandle_t register_image( const char *name, imagetype_t type ) {
+ qhandle_t handle;
+ qerror_t ret;
+
+ ret = _register_image( name, type, &handle );
+ if( handle ) {
+ return handle;
+ }
+
+ // don't spam about missing images
+ if( ret != Q_ERR_NOENT ) {
+ Com_EPrintf( "Couldn't load %s: %s\n", name, Q_ErrorString( ret ) );
+ }
+
+ return 0;
}
/*
================
-R_RegisterFont
+R_RegisterPic
================
*/
-qhandle_t R_RegisterFont( const char *name ) {
- image_t *image;
- char fullname[MAX_QPATH];
-
- if( !r_numImages ) {
- return 0;
- }
+qhandle_t R_RegisterPic( const char *name ) {
+ return register_image( name, it_pic );
+}
- if( name[0] == '/' || name[0] == '\\' ) {
- image = IMG_Find( name + 1, it_charset );
- } else {
- Q_concat( fullname, sizeof( fullname ), "pics/", name, NULL );
- COM_DefaultExtension( fullname, ".pcx", sizeof( fullname ) );
- image = IMG_Find( fullname, it_charset );
- }
+qerror_t _R_RegisterPic( const char *name, qhandle_t *handle ) {
+ return _register_image( name, it_pic, handle );
+}
- if( !image ) {
- return 0;
- }
+/*
+================
+R_RegisterFont
+================
+*/
+qhandle_t R_RegisterFont( const char *name ) {
+ return register_image( name, it_charset );
+}
- return ( image - r_images );
+qerror_t _R_RegisterFont( const char *name, qhandle_t *handle ) {
+ return _register_image( name, it_charset, handle );
}
/*
@@ -1746,13 +1816,14 @@ the colormap for software renderer.
===============
*/
void IMG_GetPalette( byte **pic ) {
- int i;
+ int i, ret;
byte pal[768], *src;
int w, h;
// get the palette
- if( !IMG_LoadPCX( "pics/colormap.pcx", pic, pal, &w, &h ) ) {
- Com_Error( ERR_FATAL, "Couldn't load pics/colormap.pcx" );
+ ret = IMG_LoadPCX( "pics/colormap.pcx", pic, pal, &w, &h );
+ if( ret < 0 ) {
+ Com_Error( ERR_FATAL, "Couldn't load pics/colormap.pcx: %s", Q_ErrorString( ret ) );
}
for( i = 0, src = pal; i < 255; i++, src += 3 ) {