r1257 - in trunk: . code/qcommon code/renderer

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Thu Feb 14 06:13:21 EST 2008


Author: ludwig
Date: 2008-02-14 06:13:18 -0500 (Thu, 14 Feb 2008)
New Revision: 1257

Added:
   trunk/code/renderer/tr_image_bmp.c
   trunk/code/renderer/tr_image_bmp.h
   trunk/code/renderer/tr_image_jpg.c
   trunk/code/renderer/tr_image_jpg.h
   trunk/code/renderer/tr_image_pcx.c
   trunk/code/renderer/tr_image_pcx.h
   trunk/code/renderer/tr_image_tga.c
   trunk/code/renderer/tr_image_tga.h
Modified:
   trunk/Makefile
   trunk/code/qcommon/qfiles.h
   trunk/code/renderer/tr_image.c
Log:
move all image decoders into separate files


Modified: trunk/Makefile
===================================================================
--- trunk/Makefile	2008-02-14 11:12:59 UTC (rev 1256)
+++ trunk/Makefile	2008-02-14 11:13:18 UTC (rev 1257)
@@ -1175,6 +1175,10 @@
   $(B)/client/tr_font.o \
   $(B)/client/tr_image.o \
   $(B)/client/tr_image_png.o \
+  $(B)/client/tr_image_jpg.o \
+  $(B)/client/tr_image_bmp.o \
+  $(B)/client/tr_image_tga.o \
+  $(B)/client/tr_image_pcx.o \
   $(B)/client/tr_init.o \
   $(B)/client/tr_light.o \
   $(B)/client/tr_main.o \

Modified: trunk/code/qcommon/qfiles.h
===================================================================
--- trunk/code/qcommon/qfiles.h	2008-02-14 11:12:59 UTC (rev 1256)
+++ trunk/code/qcommon/qfiles.h	2008-02-14 11:13:18 UTC (rev 1257)
@@ -69,53 +69,9 @@
 	int		jtrgLength;			// number of jump table targets
 } vmHeader_t;
 
-
 /*
 ========================================================================
 
-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;
-
-
-
-/*
-========================================================================
-
 .MD3 triangle model file format
 
 ========================================================================

Modified: trunk/code/renderer/tr_image.c
===================================================================
--- trunk/code/renderer/tr_image.c	2008-02-14 11:12:59 UTC (rev 1256)
+++ trunk/code/renderer/tr_image.c	2008-02-14 11:13:18 UTC (rev 1257)
@@ -22,23 +22,13 @@
 // tr_image.c
 #include "tr_local.h"
 
-/*
- * 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".
- */
 
-#define JPEG_INTERNALS
-#include "../jpeg-6/jpeglib.h"
-
+#include "tr_image_bmp.h"
+#include "tr_image_jpg.h"
+#include "tr_image_pcx.h"
 #include "tr_image_png.h"
+#include "tr_image_tga.h"
 
-static void LoadBMP( const char *name, byte **pic, int *width, int *height );
-static void LoadTGA( const char *name, byte **pic, int *width, int *height );
-static void LoadJPG( const char *name, byte **pic, int *width, int *height );
-
 static byte			 s_intensitytable[256];
 static unsigned char s_gammatable[256];
 
@@ -799,1202 +789,6 @@
 	return image;
 }
 
-
-/*
-=========================================================
-
-BMP LOADING
-
-=========================================================
-*/
-typedef struct
-{
-	char id[2];
-	unsigned fileSize;
-	unsigned reserved0;
-	unsigned bitmapDataOffset;
-	unsigned bitmapHeaderSize;
-	unsigned width;
-	unsigned height;
-	unsigned short planes;
-	unsigned short bitsPerPixel;
-	unsigned compression;
-	unsigned bitmapDataSize;
-	unsigned hRes;
-	unsigned vRes;
-	unsigned colors;
-	unsigned importantColors;
-	unsigned char palette[256][4];
-} BMPHeader_t;
-
-static void LoadBMP( const char *name, byte **pic, int *width, int *height )
-{
-	int		columns, rows;
-	unsigned	numPixels;
-	byte	*pixbuf;
-	int		row, column;
-	byte	*buf_p;
-	byte	*end;
-	byte	*buffer = NULL;
-	int		length;
-	BMPHeader_t bmpHeader;
-	byte		*bmpRGBA;
-
-	*pic = NULL;
-
-	if(width)
-		*width = 0;
-
-	if(height)
-		*height = 0;
-
-	//
-	// load the file
-	//
-	length = ri.FS_ReadFile( ( char * ) name, (void **)&buffer);
-	if (!buffer || length < 0) {
-		return;
-	}
-
-	if (length < 54)
-	{
-		ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name );
-	}
-
-	buf_p = buffer;
-	end = buffer + length;
-
-	bmpHeader.id[0] = *buf_p++;
-	bmpHeader.id[1] = *buf_p++;
-	bmpHeader.fileSize = LittleLong( * ( int * ) buf_p );
-	buf_p += 4;
-	bmpHeader.reserved0 = LittleLong( * ( int * ) buf_p );
-	buf_p += 4;
-	bmpHeader.bitmapDataOffset = LittleLong( * ( int * ) buf_p );
-	buf_p += 4;
-	bmpHeader.bitmapHeaderSize = LittleLong( * ( int * ) buf_p );
-	buf_p += 4;
-	bmpHeader.width = LittleLong( * ( int * ) buf_p );
-	buf_p += 4;
-	bmpHeader.height = LittleLong( * ( int * ) 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( * ( int * ) buf_p );
-	buf_p += 4;
-	bmpHeader.bitmapDataSize = LittleLong( * ( int * ) buf_p );
-	buf_p += 4;
-	bmpHeader.hRes = LittleLong( * ( int * ) buf_p );
-	buf_p += 4;
-	bmpHeader.vRes = LittleLong( * ( int * ) buf_p );
-	buf_p += 4;
-	bmpHeader.colors = LittleLong( * ( int * ) buf_p );
-	buf_p += 4;
-	bmpHeader.importantColors = LittleLong( * ( int * ) buf_p );
-	buf_p += 4;
-
-	if ( bmpHeader.bitsPerPixel == 8 )
-	{
-		if (buf_p + sizeof(bmpHeader.palette) > end)
-			ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name );
-
-		Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
-		buf_p += sizeof(bmpHeader.palette);
-	}
-
-	if (buffer + bmpHeader.bitmapDataOffset > end)
-	{
-		ri.Error( ERR_DROP, "LoadBMP: invalid offset value in header (%s)\n", name );
-	}
-
-	buf_p = buffer + bmpHeader.bitmapDataOffset;
-
-	if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) 
-	{
-		ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)\n", name );
-	}
-	if ( bmpHeader.fileSize != length )
-	{
-		ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%u vs. %u) (%s)\n", bmpHeader.fileSize, length, name );
-	}
-	if ( bmpHeader.compression != 0 )
-	{
-		ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)\n", name );
-	}
-	if ( bmpHeader.bitsPerPixel < 8 )
-	{
-		ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name );
-	}
-
-	switch ( bmpHeader.bitsPerPixel )
-	{
-		case 8:
-		case 16:
-		case 24:
-		case 32:
-			break;
-		default:
-			ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%hu' in file '%s'\n", bmpHeader.bitsPerPixel, name );
-			break;
-	}
-
-	columns = bmpHeader.width;
-	rows = bmpHeader.height;
-	if ( rows < 0 )
-		rows = -rows;
-	numPixels = columns * rows;
-
-	if(columns <= 0 || !rows || numPixels > 0x1FFFFFFF // 4*1FFFFFFF == 0x7FFFFFFC < 0x7FFFFFFF
-	    || ((numPixels * 4) / columns) / 4 != rows)
-	{
-	  ri.Error (ERR_DROP, "LoadBMP: %s has an invalid image size\n", name);
-	}
-	if(buf_p + numPixels*bmpHeader.bitsPerPixel/8 > end)
-	{
-	  ri.Error (ERR_DROP, "LoadBMP: file truncated (%s)\n", name);
-	}
-
-	if ( width ) 
-		*width = columns;
-	if ( height )
-		*height = rows;
-
-	bmpRGBA = ri.Malloc( 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;
-			}
-		}
-	}
-
-	ri.FS_FreeFile( buffer );
-
-}
-
-
-/*
-=================================================================
-
-PCX LOADING
-
-=================================================================
-*/
-
-
-/*
-==============
-LoadPCX
-==============
-*/
-static void LoadPCX ( const char *filename, byte **pic, byte **palette, int *width, int *height)
-{
-	byte	*raw;
-	pcx_t	*pcx;
-	int		x, y;
-	int		len;
-	int		dataByte, runLength;
-	byte	*out, *pix;
-	unsigned		xmax, ymax;
-
-	*pic = NULL;
-	*palette = NULL;
-
-	//
-	// load the file
-	//
-	len = ri.FS_ReadFile( ( char * ) filename, (void **)&raw);
-	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)
-	{
-		ri.Printf (PRINT_ALL, "Bad pcx file %s (%i x %i) (%i x %i)\n", filename, xmax+1, ymax+1, pcx->xmax, pcx->ymax);
-		return;
-	}
-
-	out = ri.Malloc ( (ymax+1) * (xmax+1) );
-
-	*pic = out;
-
-	pix = out;
-
-	if (palette)
-	{
-		*palette = ri.Malloc(768);
-		Com_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)
-	{
-		ri.Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename);
-		ri.Free (*pic);
-		*pic = NULL;
-	}
-
-	ri.FS_FreeFile (pcx);
-}
-
-
-/*
-==============
-LoadPCX32
-==============
-*/
-static void LoadPCX32 ( const char *filename, byte **pic, int *width, int *height) {
-	byte	*palette;
-	byte	*pic8;
-	int		i, c, p;
-	byte	*pic32;
-
-	LoadPCX (filename, &pic8, &palette, width, height);
-	if (!pic8) {
-		*pic = NULL;
-		return;
-	}
-
-	// LoadPCX32 ensures width, height < 1024
-	c = (*width) * (*height);
-	pic32 = *pic = ri.Malloc(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;
-	}
-
-	ri.Free (pic8);
-	ri.Free (palette);
-}
-
-/*
-=========================================================
-
-TARGA LOADING
-
-=========================================================
-*/
-
-/*
-=============
-LoadTGA
-=============
-*/
-static void LoadTGA ( const char *name, byte **pic, int *width, int *height)
-{
-	unsigned	columns, rows, numPixels;
-	byte	*pixbuf;
-	int		row, column;
-	byte	*buf_p;
-	byte	*end;
-	byte	*buffer = NULL;
-	TargaHeader	targa_header;
-	byte		*targa_rgba;
-	int length;
-
-	*pic = NULL;
-
-	if(width)
-		*width = 0;
-	if(height)
-		*height = 0;
-
-	//
-	// load the file
-	//
-	length = ri.FS_ReadFile ( ( char * ) name, (void **)&buffer);
-	if (!buffer || length < 0) {
-		return;
-	}
-
-	if(length < 18)
-	{
-		ri.Error( ERR_DROP, "LoadTGA: header too short (%s)\n", name );
-	}
-
-	buf_p = buffer;
-	end = buffer + length;
-
-	targa_header.id_length = buf_p[0];
-	targa_header.colormap_type = buf_p[1];
-	targa_header.image_type = buf_p[2];
-	
-	memcpy(&targa_header.colormap_index, &buf_p[3], 2);
-	memcpy(&targa_header.colormap_length, &buf_p[5], 2);
-	targa_header.colormap_size = buf_p[7];
-	memcpy(&targa_header.x_origin, &buf_p[8], 2);
-	memcpy(&targa_header.y_origin, &buf_p[10], 2);
-	memcpy(&targa_header.width, &buf_p[12], 2);
-	memcpy(&targa_header.height, &buf_p[14], 2);
-	targa_header.pixel_size = buf_p[16];
-	targa_header.attributes = buf_p[17];
-
-	targa_header.colormap_index = LittleShort(targa_header.colormap_index);
-	targa_header.colormap_length = LittleShort(targa_header.colormap_length);
-	targa_header.x_origin = LittleShort(targa_header.x_origin);
-	targa_header.y_origin = LittleShort(targa_header.y_origin);
-	targa_header.width = LittleShort(targa_header.width);
-	targa_header.height = LittleShort(targa_header.height);
-
-	buf_p += 18;
-
-	if (targa_header.image_type!=2 
-		&& targa_header.image_type!=10
-		&& targa_header.image_type != 3 ) 
-	{
-		ri.Error (ERR_DROP, "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
-	}
-
-	if ( targa_header.colormap_type != 0 )
-	{
-		ri.Error( ERR_DROP, "LoadTGA: colormaps not supported\n" );
-	}
-
-	if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 )
-	{
-		ri.Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
-	}
-
-	columns = targa_header.width;
-	rows = targa_header.height;
-	numPixels = columns * rows * 4;
-
-	if(!columns || !rows || numPixels > 0x7FFFFFFF || numPixels / columns / 4 != rows)
-	{
-		ri.Error (ERR_DROP, "LoadTGA: %s has an invalid image size\n", name);
-	}
-
-
-	targa_rgba = ri.Malloc (numPixels);
-
-	if (targa_header.id_length != 0)
-	{
-		if (buf_p + targa_header.id_length > end)
-			ri.Error( ERR_DROP, "LoadTGA: header too short (%s)\n", name );
-
-		buf_p += targa_header.id_length;  // skip TARGA image comment
-	}
-	
-	if ( targa_header.image_type==2 || targa_header.image_type == 3 )
-	{ 
-		if(buf_p + columns*rows*targa_header.pixel_size/8 > end)
-		{
-			ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name);
-		}
-
-		// 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:
-					ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
-					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; ) {
-				if(buf_p + 1 > end)
-					ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name);
-				packetHeader= *buf_p++;
-				packetSize = 1 + (packetHeader & 0x7f);
-				if (packetHeader & 0x80) {        // run-length packet
-					if(buf_p + targa_header.pixel_size/8 > end)
-						ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name);
-					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:
-							ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
-							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
-
-					if(buf_p + targa_header.pixel_size/8*packetSize > end)
-						ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name);
-					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:
-								ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
-								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 0 
-  // TTimo: this is the chunk of code to ensure a behavior that meets TGA specs 
-  // bit 5 set => top-down
-  if (targa_header.attributes & 0x20) {
-    unsigned char *flip = (unsigned char*)malloc (columns*4);
-    unsigned char *src, *dst;
-
-    for (row = 0; row < rows/2; row++) {
-      src = targa_rgba + row * 4 * columns;
-      dst = targa_rgba + (rows - row - 1) * 4 * columns;
-
-      memcpy (flip, src, columns*4);
-      memcpy (src, dst, columns*4);
-      memcpy (dst, flip, columns*4);
-    }
-    free (flip);
-  }
-#endif
-  // instead we just print a warning
-  if (targa_header.attributes & 0x20) {
-    ri.Printf( PRINT_WARNING, "WARNING: '%s' TGA file header declares top-down image, ignoring\n", name);
-  }
-
-  if (width)
-	  *width = columns;
-  if (height)
-	  *height = rows;
-
-  *pic = targa_rgba;
-
-  ri.FS_FreeFile (buffer);
-}
-static void LoadJPG( const char *filename, unsigned char **pic, int *width, int *height ) {
-  /* 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 = {NULL};
-  /* 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 */
-  unsigned row_stride;		/* physical row width in output buffer */
-  unsigned pixelcount, memcount;
-  unsigned char *out;
-  byte	*fbuffer;
-  byte  *buf;
-
-  /* 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.
-   */
-
-  ri.FS_ReadFile ( ( char * ) filename, (void **)&fbuffer);
-  if (!fbuffer) {
-	return;
-  }
-
-  /* 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 */
-
-  pixelcount = cinfo.output_width * cinfo.output_height;
-
-  if(!cinfo.output_width || !cinfo.output_height
-      || ((pixelcount * 4) / cinfo.output_width) / 4 != cinfo.output_height
-      || pixelcount > 0x1FFFFFFF || cinfo.output_components > 4) // 4*1FFFFFFF == 0x7FFFFFFC < 0x7FFFFFFF
-  {
-    ri.Error (ERR_DROP, "LoadJPG: %s has an invalid image size: %dx%d*4=%d, components: %d\n", filename,
-		    cinfo.output_width, cinfo.output_height, pixelcount * 4, cinfo.output_components);
-  }
-
-  memcount = pixelcount * 4;
-  row_stride = cinfo.output_width * cinfo.output_components;
-
-  out = ri.Malloc(memcount);
-
-  *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.
-     */
-	buf = ((out+(row_stride*cinfo.output_scanline)));
-	buffer = &buf;
-    (void) jpeg_read_scanlines(&cinfo, buffer, 1);
-  }
-  
-  buf = out;
-
-  // If we are processing an 8-bit JPEG (greyscale), we'll have to convert
-  // the greyscale values to RGBA.
-  if(cinfo.output_components == 1)
-  {
-  	int sindex = pixelcount, dindex = memcount;
-	unsigned char greyshade;
-
-	// Only pixelcount number of bytes have been written.
-	// Expand the color values over the rest of the buffer, starting
-	// from the end.
-	do
-	{
-		greyshade = buf[--sindex];
-
-		buf[--dindex] = 255;
-		buf[--dindex] = greyshade;
-		buf[--dindex] = greyshade;
-		buf[--dindex] = greyshade;
-	} while(sindex);
-  }
-  else
-  {
-	// clear all the alphas to 255
-	int	i;
-
-	for ( i = 3 ; i < memcount ; i+=4 )
-	{
-		buf[i] = 255;
-	}
-  }
-
-  *pic = out;
-
-  /* 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...)
-   */
-  ri.FS_FreeFile (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! */
-}
-
-
-/* Expanded data destination object for stdio output */
-
-typedef struct {
-  struct jpeg_destination_mgr pub; /* public fields */
-
-  byte* outfile;		/* target stream */
-  int	size;
-} my_destination_mgr;
-
-typedef my_destination_mgr * my_dest_ptr;
-
-
-/*
- * Initialize destination --- called by jpeg_start_compress
- * before any data is actually written.
- */
-
-void init_destination (j_compress_ptr cinfo)
-{
-  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
-
-  dest->pub.next_output_byte = dest->outfile;
-  dest->pub.free_in_buffer = dest->size;
-}
-
-
-/*
- * Empty the output buffer --- called whenever buffer fills up.
- *
- * In typical applications, this should write the entire output buffer
- * (ignoring the current state of next_output_byte & free_in_buffer),
- * reset the pointer & count to the start of the buffer, and return TRUE
- * indicating that the buffer has been dumped.
- *
- * In applications that need to be able to suspend compression due to output
- * overrun, a FALSE return indicates that the buffer cannot be emptied now.
- * In this situation, the compressor will return to its caller (possibly with
- * an indication that it has not accepted all the supplied scanlines).  The
- * application should resume compression after it has made more room in the
- * output buffer.  Note that there are substantial restrictions on the use of
- * suspension --- see the documentation.
- *
- * When suspending, the compressor will back up to a convenient restart point
- * (typically the start of the current MCU). next_output_byte & free_in_buffer
- * indicate where the restart point will be if the current call returns FALSE.
- * Data beyond this point will be regenerated after resumption, so do not
- * write it out when emptying the buffer externally.
- */
-
-boolean empty_output_buffer (j_compress_ptr cinfo)
-{
-  return TRUE;
-}
-
-
-/*
- * Compression initialization.
- * Before calling this, all parameters and a data destination must be set up.
- *
- * We require a write_all_tables parameter as a failsafe check when writing
- * multiple datastreams from the same compression object.  Since prior runs
- * will have left all the tables marked sent_table=TRUE, a subsequent run
- * would emit an abbreviated stream (no tables) by default.  This may be what
- * is wanted, but for safety's sake it should not be the default behavior:
- * programmers should have to make a deliberate choice to emit abbreviated
- * images.  Therefore the documentation and examples should encourage people
- * to pass write_all_tables=TRUE; then it will take active thought to do the
- * wrong thing.
- */
-
-GLOBAL void
-jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables)
-{
-  if (cinfo->global_state != CSTATE_START)
-    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
-  if (write_all_tables)
-    jpeg_suppress_tables(cinfo, FALSE);	/* mark all tables to be written */
-
-  /* (Re)initialize error mgr and destination modules */
-  (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
-  (*cinfo->dest->init_destination) (cinfo);
-  /* Perform master selection of active modules */
-  jinit_compress_master(cinfo);
-  /* Set up for the first pass */
-  (*cinfo->master->prepare_for_pass) (cinfo);
-  /* Ready for application to drive first pass through jpeg_write_scanlines
-   * or jpeg_write_raw_data.
-   */
-  cinfo->next_scanline = 0;
-  cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING);
-}
-
-
-/*
- * Write some scanlines of data to the JPEG compressor.
- *
- * The return value will be the number of lines actually written.
- * This should be less than the supplied num_lines only in case that
- * the data destination module has requested suspension of the compressor,
- * or if more than image_height scanlines are passed in.
- *
- * Note: we warn about excess calls to jpeg_write_scanlines() since
- * this likely signals an application programmer error.  However,
- * excess scanlines passed in the last valid call are *silently* ignored,
- * so that the application need not adjust num_lines for end-of-image
- * when using a multiple-scanline buffer.
- */
-
-GLOBAL JDIMENSION
-jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines,
-		      JDIMENSION num_lines)
-{
-  JDIMENSION row_ctr, rows_left;
-
-  if (cinfo->global_state != CSTATE_SCANNING)
-    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-  if (cinfo->next_scanline >= cinfo->image_height)
-    WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
-
-  /* Call progress monitor hook if present */
-  if (cinfo->progress != NULL) {
-    cinfo->progress->pass_counter = (long) cinfo->next_scanline;
-    cinfo->progress->pass_limit = (long) cinfo->image_height;
-    (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
-  }
-
-  /* Give master control module another chance if this is first call to
-   * jpeg_write_scanlines.  This lets output of the frame/scan headers be
-   * delayed so that application can write COM, etc, markers between
-   * jpeg_start_compress and jpeg_write_scanlines.
-   */
-  if (cinfo->master->call_pass_startup)
-    (*cinfo->master->pass_startup) (cinfo);
-
-  /* Ignore any extra scanlines at bottom of image. */
-  rows_left = cinfo->image_height - cinfo->next_scanline;
-  if (num_lines > rows_left)
-    num_lines = rows_left;
-
-  row_ctr = 0;
-  (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines);
-  cinfo->next_scanline += row_ctr;
-  return row_ctr;
-}
-
-/*
- * Terminate destination --- called by jpeg_finish_compress
- * after all data has been written.  Usually needs to flush buffer.
- *
- * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
- * application must deal with any cleanup that should happen even
- * for error exit.
- */
-
-static int hackSize;
-
-void term_destination (j_compress_ptr cinfo)
-{
-  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
-  size_t datacount = dest->size - dest->pub.free_in_buffer;
-  hackSize = datacount;
-}
-
-
-/*
- * Prepare for output to a stdio stream.
- * The caller must have already opened the stream, and is responsible
- * for closing it after finishing compression.
- */
-
-void jpegDest (j_compress_ptr cinfo, byte* outfile, int size)
-{
-  my_dest_ptr dest;
-
-  /* The destination object is made permanent so that multiple JPEG images
-   * can be written to the same file without re-executing jpeg_stdio_dest.
-   * This makes it dangerous to use this manager and a different destination
-   * manager serially with the same JPEG object, because their private object
-   * sizes may be different.  Caveat programmer.
-   */
-  if (cinfo->dest == NULL) {	/* first time for this JPEG object? */
-    cinfo->dest = (struct jpeg_destination_mgr *)
-      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
-				  sizeof(my_destination_mgr));
-  }
-
-  dest = (my_dest_ptr) cinfo->dest;
-  dest->pub.init_destination = init_destination;
-  dest->pub.empty_output_buffer = empty_output_buffer;
-  dest->pub.term_destination = term_destination;
-  dest->outfile = outfile;
-  dest->size = size;
-}
-
-void SaveJPG(char * filename, int quality, int image_width, int image_height, unsigned char *image_buffer) {
-  /* This struct contains the JPEG compression parameters and pointers to
-   * working space (which is allocated as needed by the JPEG library).
-   * It is possible to have several such structures, representing multiple
-   * compression/decompression processes, in existence at once.  We refer
-   * to any one struct (and its associated working data) as a "JPEG object".
-   */
-  struct jpeg_compress_struct cinfo;
-  /* 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 */
-  JSAMPROW row_pointer[1];	/* pointer to JSAMPLE row[s] */
-  int row_stride;		/* physical row width in image buffer */
-  unsigned char *out;
-
-  /* Step 1: allocate and initialize JPEG compression 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 compression object. */
-  jpeg_create_compress(&cinfo);
-
-  /* Step 2: specify data destination (eg, a file) */
-  /* Note: steps 2 and 3 can be done in either order. */
-
-  /* Here we use the library-supplied code to send compressed data to a
-   * stdio stream.  You can also write your own code to do something else.
-   * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
-   * requires it in order to write binary files.
-   */
-  out = ri.Hunk_AllocateTempMemory(image_width*image_height*4);
-  jpegDest(&cinfo, out, image_width*image_height*4);
-
-  /* Step 3: set parameters for compression */
-
-  /* First we supply a description of the input image.
-   * Four fields of the cinfo struct must be filled in:
-   */
-  cinfo.image_width = image_width; 	/* image width and height, in pixels */
-  cinfo.image_height = image_height;
-  cinfo.input_components = 4;		/* # of color components per pixel */
-  cinfo.in_color_space = JCS_RGB; 	/* colorspace of input image */
-  /* Now use the library's routine to set default compression parameters.
-   * (You must set at least cinfo.in_color_space before calling this,
-   * since the defaults depend on the source color space.)
-   */
-  jpeg_set_defaults(&cinfo);
-  /* Now you can set any non-default parameters you wish to.
-   * Here we just illustrate the use of quality (quantization table) scaling:
-   */
-  jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
-  /* If quality is set high, disable chroma subsampling */
-  if (quality >= 85) {
-    cinfo.comp_info[0].h_samp_factor = 1;
-    cinfo.comp_info[0].v_samp_factor = 1;
-  }
-
-  /* Step 4: Start compressor */
-
-  /* TRUE ensures that we will write a complete interchange-JPEG file.
-   * Pass TRUE unless you are very sure of what you're doing.
-   */
-  jpeg_start_compress(&cinfo, TRUE);
-
-  /* Step 5: while (scan lines remain to be written) */
-  /*           jpeg_write_scanlines(...); */
-
-  /* Here we use the library's state variable cinfo.next_scanline as the
-   * loop counter, so that we don't have to keep track ourselves.
-   * To keep things simple, we pass one scanline per call; you can pass
-   * more if you wish, though.
-   */
-  row_stride = image_width * 4;	/* JSAMPLEs per row in image_buffer */
-
-  while (cinfo.next_scanline < cinfo.image_height) {
-    /* jpeg_write_scanlines expects an array of pointers to scanlines.
-     * Here the array is only one element long, but you could pass
-     * more than one scanline at a time if that's more convenient.
-     */
-    row_pointer[0] = & image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride];
-    (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
-  }
-
-  /* Step 6: Finish compression */
-
-  jpeg_finish_compress(&cinfo);
-  /* After finish_compress, we can close the output file. */
-  ri.FS_WriteFile( filename, out, hackSize );
-
-  ri.Hunk_FreeTempMemory(out);
-
-  /* Step 7: release JPEG compression object */
-
-  /* This is an important step since it will release a good deal of memory. */
-  jpeg_destroy_compress(&cinfo);
-
-  /* And we're done! */
-}
-
-/*
-=================
-SaveJPGToBuffer
-=================
-*/
-int SaveJPGToBuffer( byte *buffer, int quality,
-    int image_width, int image_height,
-    byte *image_buffer )
-{
-  struct jpeg_compress_struct cinfo;
-  struct jpeg_error_mgr jerr;
-  JSAMPROW row_pointer[1];	/* pointer to JSAMPLE row[s] */
-  int row_stride;		/* physical row width in image buffer */
-
-  /* Step 1: allocate and initialize JPEG compression object */
-  cinfo.err = jpeg_std_error(&jerr);
-  /* Now we can initialize the JPEG compression object. */
-  jpeg_create_compress(&cinfo);
-
-  /* Step 2: specify data destination (eg, a file) */
-  /* Note: steps 2 and 3 can be done in either order. */
-  jpegDest(&cinfo, buffer, image_width*image_height*4);
-
-  /* Step 3: set parameters for compression */
-  cinfo.image_width = image_width; 	/* image width and height, in pixels */
-  cinfo.image_height = image_height;
-  cinfo.input_components = 4;		/* # 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 /* limit to baseline-JPEG values */);
-  /* If quality is set high, disable chroma subsampling */
-  if (quality >= 85) {
-    cinfo.comp_info[0].h_samp_factor = 1;
-    cinfo.comp_info[0].v_samp_factor = 1;
-  }
-
-  /* Step 4: Start compressor */
-  jpeg_start_compress(&cinfo, TRUE);
-
-  /* Step 5: while (scan lines remain to be written) */
-  /*           jpeg_write_scanlines(...); */
-  row_stride = image_width * 4;	/* JSAMPLEs per row in image_buffer */
-
-  while (cinfo.next_scanline < cinfo.image_height) {
-    /* jpeg_write_scanlines expects an array of pointers to scanlines.
-     * Here the array is only one element long, but you could pass
-     * more than one scanline at a time if that's more convenient.
-     */
-    row_pointer[0] = & image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride];
-    (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
-  }
-
-  /* Step 6: Finish compression */
-  jpeg_finish_compress(&cinfo);
-
-  /* Step 7: release JPEG compression object */
-  jpeg_destroy_compress(&cinfo);
-
-  /* And we're done! */
-  return hackSize;
-}
-
 //===================================================================
 
 typedef struct
@@ -2011,7 +805,7 @@
 	{ "jpg",  LoadJPG },
 	{ "jpeg", LoadJPG },
 	{ "png",  LoadPNG },
-	{ "pcx",  LoadPCX32 },
+	{ "pcx",  LoadPCX },
 	{ "bmp",  LoadBMP }
 };
 

Added: trunk/code/renderer/tr_image_bmp.c
===================================================================
--- trunk/code/renderer/tr_image_bmp.c	                        (rev 0)
+++ trunk/code/renderer/tr_image_bmp.c	2008-02-14 11:13:18 UTC (rev 1257)
@@ -0,0 +1,236 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena 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 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+typedef struct
+{
+	char id[2];
+	unsigned fileSize;
+	unsigned reserved0;
+	unsigned bitmapDataOffset;
+	unsigned bitmapHeaderSize;
+	unsigned width;
+	unsigned height;
+	unsigned short planes;
+	unsigned short bitsPerPixel;
+	unsigned compression;
+	unsigned bitmapDataSize;
+	unsigned hRes;
+	unsigned vRes;
+	unsigned colors;
+	unsigned importantColors;
+	unsigned char palette[256][4];
+} BMPHeader_t;
+
+void LoadBMP( const char *name, byte **pic, int *width, int *height )
+{
+	int		columns, rows;
+	unsigned	numPixels;
+	byte	*pixbuf;
+	int		row, column;
+	byte	*buf_p;
+	byte	*end;
+	byte	*buffer = NULL;
+	int		length;
+	BMPHeader_t bmpHeader;
+	byte		*bmpRGBA;
+
+	*pic = NULL;
+
+	if(width)
+		*width = 0;
+
+	if(height)
+		*height = 0;
+
+	//
+	// load the file
+	//
+	length = ri.FS_ReadFile( ( char * ) name, (void **)&buffer);
+	if (!buffer || length < 0) {
+		return;
+	}
+
+	if (length < 54)
+	{
+		ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name );
+	}
+
+	buf_p = buffer;
+	end = buffer + length;
+
+	bmpHeader.id[0] = *buf_p++;
+	bmpHeader.id[1] = *buf_p++;
+	bmpHeader.fileSize = LittleLong( * ( int * ) buf_p );
+	buf_p += 4;
+	bmpHeader.reserved0 = LittleLong( * ( int * ) buf_p );
+	buf_p += 4;
+	bmpHeader.bitmapDataOffset = LittleLong( * ( int * ) buf_p );
+	buf_p += 4;
+	bmpHeader.bitmapHeaderSize = LittleLong( * ( int * ) buf_p );
+	buf_p += 4;
+	bmpHeader.width = LittleLong( * ( int * ) buf_p );
+	buf_p += 4;
+	bmpHeader.height = LittleLong( * ( int * ) 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( * ( int * ) buf_p );
+	buf_p += 4;
+	bmpHeader.bitmapDataSize = LittleLong( * ( int * ) buf_p );
+	buf_p += 4;
+	bmpHeader.hRes = LittleLong( * ( int * ) buf_p );
+	buf_p += 4;
+	bmpHeader.vRes = LittleLong( * ( int * ) buf_p );
+	buf_p += 4;
+	bmpHeader.colors = LittleLong( * ( int * ) buf_p );
+	buf_p += 4;
+	bmpHeader.importantColors = LittleLong( * ( int * ) buf_p );
+	buf_p += 4;
+
+	if ( bmpHeader.bitsPerPixel == 8 )
+	{
+		if (buf_p + sizeof(bmpHeader.palette) > end)
+			ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name );
+
+		Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
+		buf_p += sizeof(bmpHeader.palette);
+	}
+
+	if (buffer + bmpHeader.bitmapDataOffset > end)
+	{
+		ri.Error( ERR_DROP, "LoadBMP: invalid offset value in header (%s)\n", name );
+	}
+
+	buf_p = buffer + bmpHeader.bitmapDataOffset;
+
+	if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) 
+	{
+		ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)\n", name );
+	}
+	if ( bmpHeader.fileSize != length )
+	{
+		ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%u vs. %u) (%s)\n", bmpHeader.fileSize, length, name );
+	}
+	if ( bmpHeader.compression != 0 )
+	{
+		ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)\n", name );
+	}
+	if ( bmpHeader.bitsPerPixel < 8 )
+	{
+		ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name );
+	}
+
+	switch ( bmpHeader.bitsPerPixel )
+	{
+		case 8:
+		case 16:
+		case 24:
+		case 32:
+			break;
+		default:
+			ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%hu' in file '%s'\n", bmpHeader.bitsPerPixel, name );
+			break;
+	}
+
+	columns = bmpHeader.width;
+	rows = bmpHeader.height;
+	if ( rows < 0 )
+		rows = -rows;
+	numPixels = columns * rows;
+
+	if(columns <= 0 || !rows || numPixels > 0x1FFFFFFF // 4*1FFFFFFF == 0x7FFFFFFC < 0x7FFFFFFF
+	    || ((numPixels * 4) / columns) / 4 != rows)
+	{
+	  ri.Error (ERR_DROP, "LoadBMP: %s has an invalid image size\n", name);
+	}
+	if(buf_p + numPixels*bmpHeader.bitsPerPixel/8 > end)
+	{
+	  ri.Error (ERR_DROP, "LoadBMP: file truncated (%s)\n", name);
+	}
+
+	if ( width ) 
+		*width = columns;
+	if ( height )
+		*height = rows;
+
+	bmpRGBA = ri.Malloc( 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;
+			}
+		}
+	}
+
+	ri.FS_FreeFile( buffer );
+
+}

Added: trunk/code/renderer/tr_image_bmp.h
===================================================================
--- trunk/code/renderer/tr_image_bmp.h	                        (rev 0)
+++ trunk/code/renderer/tr_image_bmp.h	2008-02-14 11:13:18 UTC (rev 1257)
@@ -0,0 +1 @@
+void LoadBMP( const char *name, byte **pic, int *width, int *height );

Added: trunk/code/renderer/tr_image_jpg.c
===================================================================
--- trunk/code/renderer/tr_image_jpg.c	                        (rev 0)
+++ trunk/code/renderer/tr_image_jpg.c	2008-02-14 11:13:18 UTC (rev 1257)
@@ -0,0 +1,581 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena 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 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+/*
+ * 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".
+ */
+
+#define JPEG_INTERNALS
+#include "../jpeg-6/jpeglib.h"
+
+void LoadJPG( const char *filename, unsigned char **pic, int *width, int *height ) {
+  /* 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 = {NULL};
+  /* 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 */
+  unsigned row_stride;		/* physical row width in output buffer */
+  unsigned pixelcount, memcount;
+  unsigned char *out;
+  byte	*fbuffer;
+  byte  *buf;
+
+  /* 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.
+   */
+
+  ri.FS_ReadFile ( ( char * ) filename, (void **)&fbuffer);
+  if (!fbuffer) {
+	return;
+  }
+
+  /* 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 */
+
+  pixelcount = cinfo.output_width * cinfo.output_height;
+
+  if(!cinfo.output_width || !cinfo.output_height
+      || ((pixelcount * 4) / cinfo.output_width) / 4 != cinfo.output_height
+      || pixelcount > 0x1FFFFFFF || cinfo.output_components > 4) // 4*1FFFFFFF == 0x7FFFFFFC < 0x7FFFFFFF
+  {
+    ri.Error (ERR_DROP, "LoadJPG: %s has an invalid image size: %dx%d*4=%d, components: %d\n", filename,
+		    cinfo.output_width, cinfo.output_height, pixelcount * 4, cinfo.output_components);
+  }
+
+  memcount = pixelcount * 4;
+  row_stride = cinfo.output_width * cinfo.output_components;
+
+  out = ri.Malloc(memcount);
+
+  *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.
+     */
+	buf = ((out+(row_stride*cinfo.output_scanline)));
+	buffer = &buf;
+    (void) jpeg_read_scanlines(&cinfo, buffer, 1);
+  }
+  
+  buf = out;
+
+  // If we are processing an 8-bit JPEG (greyscale), we'll have to convert
+  // the greyscale values to RGBA.
+  if(cinfo.output_components == 1)
+  {
+  	int sindex = pixelcount, dindex = memcount;
+	unsigned char greyshade;
+
+	// Only pixelcount number of bytes have been written.
+	// Expand the color values over the rest of the buffer, starting
+	// from the end.
+	do
+	{
+		greyshade = buf[--sindex];
+
+		buf[--dindex] = 255;
+		buf[--dindex] = greyshade;
+		buf[--dindex] = greyshade;
+		buf[--dindex] = greyshade;
+	} while(sindex);
+  }
+  else
+  {
+	// clear all the alphas to 255
+	int	i;
+
+	for ( i = 3 ; i < memcount ; i+=4 )
+	{
+		buf[i] = 255;
+	}
+  }
+
+  *pic = out;
+
+  /* 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...)
+   */
+  ri.FS_FreeFile (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! */
+}
+
+
+/* Expanded data destination object for stdio output */
+
+typedef struct {
+  struct jpeg_destination_mgr pub; /* public fields */
+
+  byte* outfile;		/* target stream */
+  int	size;
+} my_destination_mgr;
+
+typedef my_destination_mgr * my_dest_ptr;
+
+
+/*
+ * Initialize destination --- called by jpeg_start_compress
+ * before any data is actually written.
+ */
+
+void init_destination (j_compress_ptr cinfo)
+{
+  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+  dest->pub.next_output_byte = dest->outfile;
+  dest->pub.free_in_buffer = dest->size;
+}
+
+
+/*
+ * Empty the output buffer --- called whenever buffer fills up.
+ *
+ * In typical applications, this should write the entire output buffer
+ * (ignoring the current state of next_output_byte & free_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been dumped.
+ *
+ * In applications that need to be able to suspend compression due to output
+ * overrun, a FALSE return indicates that the buffer cannot be emptied now.
+ * In this situation, the compressor will return to its caller (possibly with
+ * an indication that it has not accepted all the supplied scanlines).  The
+ * application should resume compression after it has made more room in the
+ * output buffer.  Note that there are substantial restrictions on the use of
+ * suspension --- see the documentation.
+ *
+ * When suspending, the compressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_output_byte & free_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point will be regenerated after resumption, so do not
+ * write it out when emptying the buffer externally.
+ */
+
+boolean empty_output_buffer (j_compress_ptr cinfo)
+{
+  return TRUE;
+}
+
+
+/*
+ * Compression initialization.
+ * Before calling this, all parameters and a data destination must be set up.
+ *
+ * We require a write_all_tables parameter as a failsafe check when writing
+ * multiple datastreams from the same compression object.  Since prior runs
+ * will have left all the tables marked sent_table=TRUE, a subsequent run
+ * would emit an abbreviated stream (no tables) by default.  This may be what
+ * is wanted, but for safety's sake it should not be the default behavior:
+ * programmers should have to make a deliberate choice to emit abbreviated
+ * images.  Therefore the documentation and examples should encourage people
+ * to pass write_all_tables=TRUE; then it will take active thought to do the
+ * wrong thing.
+ */
+
+GLOBAL void
+jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables)
+{
+  if (cinfo->global_state != CSTATE_START)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+  if (write_all_tables)
+    jpeg_suppress_tables(cinfo, FALSE);	/* mark all tables to be written */
+
+  /* (Re)initialize error mgr and destination modules */
+  (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+  (*cinfo->dest->init_destination) (cinfo);
+  /* Perform master selection of active modules */
+  jinit_compress_master(cinfo);
+  /* Set up for the first pass */
+  (*cinfo->master->prepare_for_pass) (cinfo);
+  /* Ready for application to drive first pass through jpeg_write_scanlines
+   * or jpeg_write_raw_data.
+   */
+  cinfo->next_scanline = 0;
+  cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING);
+}
+
+
+/*
+ * Write some scanlines of data to the JPEG compressor.
+ *
+ * The return value will be the number of lines actually written.
+ * This should be less than the supplied num_lines only in case that
+ * the data destination module has requested suspension of the compressor,
+ * or if more than image_height scanlines are passed in.
+ *
+ * Note: we warn about excess calls to jpeg_write_scanlines() since
+ * this likely signals an application programmer error.  However,
+ * excess scanlines passed in the last valid call are *silently* ignored,
+ * so that the application need not adjust num_lines for end-of-image
+ * when using a multiple-scanline buffer.
+ */
+
+GLOBAL JDIMENSION
+jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines,
+		      JDIMENSION num_lines)
+{
+  JDIMENSION row_ctr, rows_left;
+
+  if (cinfo->global_state != CSTATE_SCANNING)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  if (cinfo->next_scanline >= cinfo->image_height)
+    WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+
+  /* Call progress monitor hook if present */
+  if (cinfo->progress != NULL) {
+    cinfo->progress->pass_counter = (long) cinfo->next_scanline;
+    cinfo->progress->pass_limit = (long) cinfo->image_height;
+    (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+  }
+
+  /* Give master control module another chance if this is first call to
+   * jpeg_write_scanlines.  This lets output of the frame/scan headers be
+   * delayed so that application can write COM, etc, markers between
+   * jpeg_start_compress and jpeg_write_scanlines.
+   */
+  if (cinfo->master->call_pass_startup)
+    (*cinfo->master->pass_startup) (cinfo);
+
+  /* Ignore any extra scanlines at bottom of image. */
+  rows_left = cinfo->image_height - cinfo->next_scanline;
+  if (num_lines > rows_left)
+    num_lines = rows_left;
+
+  row_ctr = 0;
+  (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines);
+  cinfo->next_scanline += row_ctr;
+  return row_ctr;
+}
+
+/*
+ * Terminate destination --- called by jpeg_finish_compress
+ * after all data has been written.  Usually needs to flush buffer.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+static int hackSize;
+
+void term_destination (j_compress_ptr cinfo)
+{
+  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+  size_t datacount = dest->size - dest->pub.free_in_buffer;
+  hackSize = datacount;
+}
+
+
+/*
+ * Prepare for output to a stdio stream.
+ * The caller must have already opened the stream, and is responsible
+ * for closing it after finishing compression.
+ */
+
+void jpegDest (j_compress_ptr cinfo, byte* outfile, int size)
+{
+  my_dest_ptr dest;
+
+  /* The destination object is made permanent so that multiple JPEG images
+   * can be written to the same file without re-executing jpeg_stdio_dest.
+   * This makes it dangerous to use this manager and a different destination
+   * manager serially with the same JPEG object, because their private object
+   * sizes may be different.  Caveat programmer.
+   */
+  if (cinfo->dest == NULL) {	/* first time for this JPEG object? */
+    cinfo->dest = (struct jpeg_destination_mgr *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+				  sizeof(my_destination_mgr));
+  }
+
+  dest = (my_dest_ptr) cinfo->dest;
+  dest->pub.init_destination = init_destination;
+  dest->pub.empty_output_buffer = empty_output_buffer;
+  dest->pub.term_destination = term_destination;
+  dest->outfile = outfile;
+  dest->size = size;
+}
+
+void SaveJPG(char * filename, int quality, int image_width, int image_height, unsigned char *image_buffer) {
+  /* This struct contains the JPEG compression parameters and pointers to
+   * working space (which is allocated as needed by the JPEG library).
+   * It is possible to have several such structures, representing multiple
+   * compression/decompression processes, in existence at once.  We refer
+   * to any one struct (and its associated working data) as a "JPEG object".
+   */
+  struct jpeg_compress_struct cinfo;
+  /* 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 */
+  JSAMPROW row_pointer[1];	/* pointer to JSAMPLE row[s] */
+  int row_stride;		/* physical row width in image buffer */
+  unsigned char *out;
+
+  /* Step 1: allocate and initialize JPEG compression 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 compression object. */
+  jpeg_create_compress(&cinfo);
+
+  /* Step 2: specify data destination (eg, a file) */
+  /* Note: steps 2 and 3 can be done in either order. */
+
+  /* Here we use the library-supplied code to send compressed data to a
+   * stdio stream.  You can also write your own code to do something else.
+   * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
+   * requires it in order to write binary files.
+   */
+  out = ri.Hunk_AllocateTempMemory(image_width*image_height*4);
+  jpegDest(&cinfo, out, image_width*image_height*4);
+
+  /* Step 3: set parameters for compression */
+
+  /* First we supply a description of the input image.
+   * Four fields of the cinfo struct must be filled in:
+   */
+  cinfo.image_width = image_width; 	/* image width and height, in pixels */
+  cinfo.image_height = image_height;
+  cinfo.input_components = 4;		/* # of color components per pixel */
+  cinfo.in_color_space = JCS_RGB; 	/* colorspace of input image */
+  /* Now use the library's routine to set default compression parameters.
+   * (You must set at least cinfo.in_color_space before calling this,
+   * since the defaults depend on the source color space.)
+   */
+  jpeg_set_defaults(&cinfo);
+  /* Now you can set any non-default parameters you wish to.
+   * Here we just illustrate the use of quality (quantization table) scaling:
+   */
+  jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
+  /* If quality is set high, disable chroma subsampling */
+  if (quality >= 85) {
+    cinfo.comp_info[0].h_samp_factor = 1;
+    cinfo.comp_info[0].v_samp_factor = 1;
+  }
+
+  /* Step 4: Start compressor */
+
+  /* TRUE ensures that we will write a complete interchange-JPEG file.
+   * Pass TRUE unless you are very sure of what you're doing.
+   */
+  jpeg_start_compress(&cinfo, TRUE);
+
+  /* Step 5: while (scan lines remain to be written) */
+  /*           jpeg_write_scanlines(...); */
+
+  /* Here we use the library's state variable cinfo.next_scanline as the
+   * loop counter, so that we don't have to keep track ourselves.
+   * To keep things simple, we pass one scanline per call; you can pass
+   * more if you wish, though.
+   */
+  row_stride = image_width * 4;	/* JSAMPLEs per row in image_buffer */
+
+  while (cinfo.next_scanline < cinfo.image_height) {
+    /* jpeg_write_scanlines expects an array of pointers to scanlines.
+     * Here the array is only one element long, but you could pass
+     * more than one scanline at a time if that's more convenient.
+     */
+    row_pointer[0] = & image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride];
+    (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+  }
+
+  /* Step 6: Finish compression */
+
+  jpeg_finish_compress(&cinfo);
+  /* After finish_compress, we can close the output file. */
+  ri.FS_WriteFile( filename, out, hackSize );
+
+  ri.Hunk_FreeTempMemory(out);
+
+  /* Step 7: release JPEG compression object */
+
+  /* This is an important step since it will release a good deal of memory. */
+  jpeg_destroy_compress(&cinfo);
+
+  /* And we're done! */
+}
+
+/*
+=================
+SaveJPGToBuffer
+=================
+*/
+int SaveJPGToBuffer( byte *buffer, int quality,
+    int image_width, int image_height,
+    byte *image_buffer )
+{
+  struct jpeg_compress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  JSAMPROW row_pointer[1];	/* pointer to JSAMPLE row[s] */
+  int row_stride;		/* physical row width in image buffer */
+
+  /* Step 1: allocate and initialize JPEG compression object */
+  cinfo.err = jpeg_std_error(&jerr);
+  /* Now we can initialize the JPEG compression object. */
+  jpeg_create_compress(&cinfo);
+
+  /* Step 2: specify data destination (eg, a file) */
+  /* Note: steps 2 and 3 can be done in either order. */
+  jpegDest(&cinfo, buffer, image_width*image_height*4);
+
+  /* Step 3: set parameters for compression */
+  cinfo.image_width = image_width; 	/* image width and height, in pixels */
+  cinfo.image_height = image_height;
+  cinfo.input_components = 4;		/* # 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 /* limit to baseline-JPEG values */);
+  /* If quality is set high, disable chroma subsampling */
+  if (quality >= 85) {
+    cinfo.comp_info[0].h_samp_factor = 1;
+    cinfo.comp_info[0].v_samp_factor = 1;
+  }
+
+  /* Step 4: Start compressor */
+  jpeg_start_compress(&cinfo, TRUE);
+
+  /* Step 5: while (scan lines remain to be written) */
+  /*           jpeg_write_scanlines(...); */
+  row_stride = image_width * 4;	/* JSAMPLEs per row in image_buffer */
+
+  while (cinfo.next_scanline < cinfo.image_height) {
+    /* jpeg_write_scanlines expects an array of pointers to scanlines.
+     * Here the array is only one element long, but you could pass
+     * more than one scanline at a time if that's more convenient.
+     */
+    row_pointer[0] = & image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride];
+    (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+  }
+
+  /* Step 6: Finish compression */
+  jpeg_finish_compress(&cinfo);
+
+  /* Step 7: release JPEG compression object */
+  jpeg_destroy_compress(&cinfo);
+
+  /* And we're done! */
+  return hackSize;
+}

Added: trunk/code/renderer/tr_image_jpg.h
===================================================================
--- trunk/code/renderer/tr_image_jpg.h	                        (rev 0)
+++ trunk/code/renderer/tr_image_jpg.h	2008-02-14 11:13:18 UTC (rev 1257)
@@ -0,0 +1 @@
+void LoadJPG( const char *name, byte **pic, int *width, int *height );

Added: trunk/code/renderer/tr_image_pcx.c
===================================================================
--- trunk/code/renderer/tr_image_pcx.c	                        (rev 0)
+++ trunk/code/renderer/tr_image_pcx.c	2008-02-14 11:13:18 UTC (rev 1257)
@@ -0,0 +1,166 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena 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 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+/*
+========================================================================
+
+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;
+
+
+static void _LoadPCX ( const char *filename, byte **pic, byte **palette, int *width, int *height)
+{
+	byte	*raw;
+	pcx_t	*pcx;
+	int		x, y;
+	int		len;
+	int		dataByte, runLength;
+	byte	*out, *pix;
+	unsigned		xmax, ymax;
+
+	*pic = NULL;
+	*palette = NULL;
+
+	//
+	// load the file
+	//
+	len = ri.FS_ReadFile( ( char * ) filename, (void **)&raw);
+	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)
+	{
+		ri.Printf (PRINT_ALL, "Bad pcx file %s (%i x %i) (%i x %i)\n", filename, xmax+1, ymax+1, pcx->xmax, pcx->ymax);
+		return;
+	}
+
+	out = ri.Malloc ( (ymax+1) * (xmax+1) );
+
+	*pic = out;
+
+	pix = out;
+
+	if (palette)
+	{
+		*palette = ri.Malloc(768);
+		Com_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)
+	{
+		ri.Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename);
+		ri.Free (*pic);
+		*pic = NULL;
+	}
+
+	ri.FS_FreeFile (pcx);
+}
+
+
+void LoadPCX ( const char *filename, byte **pic, int *width, int *height) {
+	byte	*palette;
+	byte	*pic8;
+	int		i, c, p;
+	byte	*pic32;
+
+	_LoadPCX (filename, &pic8, &palette, width, height);
+	if (!pic8) {
+		*pic = NULL;
+		return;
+	}
+
+	// LoadPCX32 ensures width, height < 1024
+	c = (*width) * (*height);
+	pic32 = *pic = ri.Malloc(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;
+	}
+
+	ri.Free (pic8);
+	ri.Free (palette);
+}

Added: trunk/code/renderer/tr_image_pcx.h
===================================================================
--- trunk/code/renderer/tr_image_pcx.h	                        (rev 0)
+++ trunk/code/renderer/tr_image_pcx.h	2008-02-14 11:13:18 UTC (rev 1257)
@@ -0,0 +1 @@
+void LoadPCX( const char *name, byte **pic, int *width, int *height );

Added: trunk/code/renderer/tr_image_tga.c
===================================================================
--- trunk/code/renderer/tr_image_tga.c	                        (rev 0)
+++ trunk/code/renderer/tr_image_tga.c	2008-02-14 11:13:18 UTC (rev 1257)
@@ -0,0 +1,317 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena 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 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+/*
+========================================================================
+
+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;
+
+void LoadTGA ( const char *name, byte **pic, int *width, int *height)
+{
+	unsigned	columns, rows, numPixels;
+	byte	*pixbuf;
+	int		row, column;
+	byte	*buf_p;
+	byte	*end;
+	byte	*buffer = NULL;
+	TargaHeader	targa_header;
+	byte		*targa_rgba;
+	int length;
+
+	*pic = NULL;
+
+	if(width)
+		*width = 0;
+	if(height)
+		*height = 0;
+
+	//
+	// load the file
+	//
+	length = ri.FS_ReadFile ( ( char * ) name, (void **)&buffer);
+	if (!buffer || length < 0) {
+		return;
+	}
+
+	if(length < 18)
+	{
+		ri.Error( ERR_DROP, "LoadTGA: header too short (%s)\n", name );
+	}
+
+	buf_p = buffer;
+	end = buffer + length;
+
+	targa_header.id_length = buf_p[0];
+	targa_header.colormap_type = buf_p[1];
+	targa_header.image_type = buf_p[2];
+	
+	memcpy(&targa_header.colormap_index, &buf_p[3], 2);
+	memcpy(&targa_header.colormap_length, &buf_p[5], 2);
+	targa_header.colormap_size = buf_p[7];
+	memcpy(&targa_header.x_origin, &buf_p[8], 2);
+	memcpy(&targa_header.y_origin, &buf_p[10], 2);
+	memcpy(&targa_header.width, &buf_p[12], 2);
+	memcpy(&targa_header.height, &buf_p[14], 2);
+	targa_header.pixel_size = buf_p[16];
+	targa_header.attributes = buf_p[17];
+
+	targa_header.colormap_index = LittleShort(targa_header.colormap_index);
+	targa_header.colormap_length = LittleShort(targa_header.colormap_length);
+	targa_header.x_origin = LittleShort(targa_header.x_origin);
+	targa_header.y_origin = LittleShort(targa_header.y_origin);
+	targa_header.width = LittleShort(targa_header.width);
+	targa_header.height = LittleShort(targa_header.height);
+
+	buf_p += 18;
+
+	if (targa_header.image_type!=2 
+		&& targa_header.image_type!=10
+		&& targa_header.image_type != 3 ) 
+	{
+		ri.Error (ERR_DROP, "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
+	}
+
+	if ( targa_header.colormap_type != 0 )
+	{
+		ri.Error( ERR_DROP, "LoadTGA: colormaps not supported\n" );
+	}
+
+	if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 )
+	{
+		ri.Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
+	}
+
+	columns = targa_header.width;
+	rows = targa_header.height;
+	numPixels = columns * rows * 4;
+
+	if(!columns || !rows || numPixels > 0x7FFFFFFF || numPixels / columns / 4 != rows)
+	{
+		ri.Error (ERR_DROP, "LoadTGA: %s has an invalid image size\n", name);
+	}
+
+
+	targa_rgba = ri.Malloc (numPixels);
+
+	if (targa_header.id_length != 0)
+	{
+		if (buf_p + targa_header.id_length > end)
+			ri.Error( ERR_DROP, "LoadTGA: header too short (%s)\n", name );
+
+		buf_p += targa_header.id_length;  // skip TARGA image comment
+	}
+	
+	if ( targa_header.image_type==2 || targa_header.image_type == 3 )
+	{ 
+		if(buf_p + columns*rows*targa_header.pixel_size/8 > end)
+		{
+			ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name);
+		}
+
+		// 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:
+					ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
+					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; ) {
+				if(buf_p + 1 > end)
+					ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name);
+				packetHeader= *buf_p++;
+				packetSize = 1 + (packetHeader & 0x7f);
+				if (packetHeader & 0x80) {        // run-length packet
+					if(buf_p + targa_header.pixel_size/8 > end)
+						ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name);
+					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:
+							ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
+							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
+
+					if(buf_p + targa_header.pixel_size/8*packetSize > end)
+						ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name);
+					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:
+								ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
+								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 0 
+  // TTimo: this is the chunk of code to ensure a behavior that meets TGA specs 
+  // bit 5 set => top-down
+  if (targa_header.attributes & 0x20) {
+    unsigned char *flip = (unsigned char*)malloc (columns*4);
+    unsigned char *src, *dst;
+
+    for (row = 0; row < rows/2; row++) {
+      src = targa_rgba + row * 4 * columns;
+      dst = targa_rgba + (rows - row - 1) * 4 * columns;
+
+      memcpy (flip, src, columns*4);
+      memcpy (src, dst, columns*4);
+      memcpy (dst, flip, columns*4);
+    }
+    free (flip);
+  }
+#endif
+  // instead we just print a warning
+  if (targa_header.attributes & 0x20) {
+    ri.Printf( PRINT_WARNING, "WARNING: '%s' TGA file header declares top-down image, ignoring\n", name);
+  }
+
+  if (width)
+	  *width = columns;
+  if (height)
+	  *height = rows;
+
+  *pic = targa_rgba;
+
+  ri.FS_FreeFile (buffer);
+}

Added: trunk/code/renderer/tr_image_tga.h
===================================================================
--- trunk/code/renderer/tr_image_tga.h	                        (rev 0)
+++ trunk/code/renderer/tr_image_tga.h	2008-02-14 11:13:18 UTC (rev 1257)
@@ -0,0 +1 @@
+void LoadTGA( const char *name, byte **pic, int *width, int *height );




More information about the quake3-commits mailing list