]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - image.c
increased build number to 103
[xonotic/darkplaces.git] / image.c
diff --git a/image.c b/image.c
index f4520e98da81c62aa1633217a2991d2fb8e2fdaa..068d01bdf5f320c8a967f356d79fc92cedf690bc 100644 (file)
--- a/image.c
+++ b/image.c
@@ -46,10 +46,10 @@ void Image_CopyRGBAGamma(byte *in, byte *out, int pixels)
 {
        while (pixels--)
        {
-               out[0] = qgamma[in[0]];
-               out[1] = qgamma[in[1]];
-               out[2] = qgamma[in[2]];
-               out[3] =        in[3] ;
+               out[0] = texgamma[in[0]];
+               out[1] = texgamma[in[1]];
+               out[2] = texgamma[in[2]];
+               out[3] =          in[3] ;
                in += 4;
                out += 4;
        }
@@ -78,7 +78,6 @@ typedef struct
     unsigned short     bytes_per_line;
     unsigned short     palette_type;
     char       filler[58];
-    unsigned   data;                   // unbounded
 } pcx_t;
 
 /*
@@ -86,91 +85,90 @@ typedef struct
 LoadPCX
 ============
 */
-byte* LoadPCX (FILE *f, int matchwidth, int matchheight)
+byte* LoadPCX (byte *f, int matchwidth, int matchheight)
 {
-       pcx_t   *pcx, pcxbuf;
-       byte    palette[768];
-       byte    *pix, *image_rgba;
-       int             x, y;
-       int             dataByte, runLength;
-       int             count;
+       pcx_t   pcx;
+       byte    *palette, *a, *b, *image_rgba, *fin, *pbuf;
+       int             x, y, dataByte, runLength;
 
-//
-// parse the PCX file
-//
-       fread (&pcxbuf, 1, sizeof(pcxbuf), f);
+       fin = f;
 
-       pcx = &pcxbuf;
+       memcpy(&pcx, fin, sizeof(pcx));
+       fin += sizeof(pcx);
 
        // LordHavoc: big-endian support ported from QF newtree
-       pcx->xmax = LittleShort (pcx->xmax);
-       pcx->xmin = LittleShort (pcx->xmin);
-       pcx->ymax = LittleShort (pcx->ymax);
-       pcx->ymin = LittleShort (pcx->ymin);
-       pcx->hres = LittleShort (pcx->hres);
-       pcx->vres = LittleShort (pcx->vres);
-       pcx->bytes_per_line = LittleShort (pcx->bytes_per_line);
-       pcx->palette_type = LittleShort (pcx->palette_type);
-
-       if (pcx->manufacturer != 0x0a || pcx->version != 5 || pcx->encoding != 1 || pcx->bits_per_pixel != 8 || pcx->xmax > 320 || pcx->ymax > 256)
+       pcx.xmax = LittleShort (pcx.xmax);
+       pcx.xmin = LittleShort (pcx.xmin);
+       pcx.ymax = LittleShort (pcx.ymax);
+       pcx.ymin = LittleShort (pcx.ymin);
+       pcx.hres = LittleShort (pcx.hres);
+       pcx.vres = LittleShort (pcx.vres);
+       pcx.bytes_per_line = LittleShort (pcx.bytes_per_line);
+       pcx.palette_type = LittleShort (pcx.palette_type);
+
+       if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1 || pcx.bits_per_pixel != 8 || pcx.xmax > 320 || pcx.ymax > 256)
        {
                Con_Printf ("Bad pcx file\n");
+               qfree(f);
                return NULL;
        }
 
-       if (matchwidth && (pcx->xmax+1) != matchwidth)
+       if (matchwidth && (pcx.xmax+1) != matchwidth)
+       {
+               qfree(f);
                return NULL;
-       if (matchheight && (pcx->ymax+1) != matchheight)
+       }
+       if (matchheight && (pcx.ymax+1) != matchheight)
+       {
+               qfree(f);
                return NULL;
+       }
 
-       // seek to palette
-       fseek (f, -768, SEEK_END);
-       fread (palette, 1, 768, f);
-
-       fseek (f, sizeof(pcxbuf) - 4, SEEK_SET);
+       image_width = pcx.xmax+1;
+       image_height = pcx.ymax+1;
 
-       count = (pcx->xmax+1) * (pcx->ymax+1);
-       image_rgba = malloc( count * 4);
+       image_rgba = qmalloc(image_width*image_height*4);
+       pbuf = image_rgba + image_width*image_height*3;
 
-       for (y=0 ; y<=pcx->ymax ; y++)
+       for (y = 0;y < image_height;y++)
        {
-               pix = image_rgba + 4*y*(pcx->xmax+1);
-               for (x=0 ; x<=pcx->xmax ; )
+               a = pbuf + y * image_width;
+               for (x = 0;x < image_width;)
                {
-                       dataByte = fgetc(f);
-
-                       if((dataByte & 0xC0) == 0xC0)
+                       dataByte = *fin++;
+                       if(dataByte >= 0xC0)
                        {
                                runLength = dataByte & 0x3F;
-                               dataByte = fgetc(f);
+                               dataByte = *fin++;
                                if (runLength)
                                {
                                        x += runLength;
                                        while(runLength--)
-                                       {
-                                               pix[0] = palette[dataByte*3];
-                                               pix[1] = palette[dataByte*3+1];
-                                               pix[2] = palette[dataByte*3+2];
-                                               pix[3] = 255;
-                                               pix += 4;
-                                       }
+                                               *a++ = dataByte;
                                }
                        }
                        else
                        {
                                x++;
-                               pix[0] = palette[dataByte*3];
-                               pix[1] = palette[dataByte*3+1];
-                               pix[2] = palette[dataByte*3+2];
-                               pix[3] = 255;
-                               pix += 4;
+                               *a++ = dataByte;
                        }
-
                }
        }
-       fclose(f);
-       image_width = pcx->xmax+1;
-       image_height = pcx->ymax+1;
+
+       palette = fin;
+       a = pbuf;
+       b = image_rgba;
+
+       for(x = 0;x < image_width*image_height;x++)
+       {
+               y = *b++ * 3;
+               *a++ = palette[y];
+               *a++ = palette[y+1];
+               *a++ = palette[y+2];
+               *a++ = 255;
+       }
+
+       qfree(f);
        return image_rgba;
 }
 
@@ -182,38 +180,17 @@ TARGA LOADING
 =========================================================
 */
 
-typedef struct _TargaHeader {
+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;
-
-
-TargaHeader            targa_header;
-
-int fgetLittleShort (FILE *f)
-{
-       byte    b1, b2;
-
-       b1 = fgetc(f);
-       b2 = fgetc(f);
-
-       return (short)(b1 + b2*256);
 }
+TargaHeader;
 
-int fgetLittleLong (FILE *f)
-{
-       byte    b1, b2, b3, b4;
-
-       b1 = fgetc(f);
-       b2 = fgetc(f);
-       b3 = fgetc(f);
-       b4 = fgetc(f);
-
-       return b1 + (b2<<8) + (b3<<16) + (b4<<24);
-}
+TargaHeader            targa_header;
 
 
 /*
@@ -221,148 +198,154 @@ int fgetLittleLong (FILE *f)
 LoadTGA
 =============
 */
-byte* LoadTGA (FILE *fin, int matchwidth, int matchheight)
+byte* LoadTGA (byte *f, int matchwidth, int matchheight)
 {
-       int                             columns, rows, numPixels;
-       byte                    *pixbuf;
-       int                             row, column;
-       byte                    *image_rgba;
-
-       targa_header.id_length = fgetc(fin);
-       targa_header.colormap_type = fgetc(fin);
-       targa_header.image_type = fgetc(fin);
+       int columns, rows, numPixels, row, column;
+       byte *pixbuf, *image_rgba, *fin;
+
+       targa_header.id_length = f[0];
+       targa_header.colormap_type = f[1];
+       targa_header.image_type = f[2];
        
-       targa_header.colormap_index = fgetLittleShort(fin);
-       targa_header.colormap_length = fgetLittleShort(fin);
-       targa_header.colormap_size = fgetc(fin);
-       targa_header.x_origin = fgetLittleShort(fin);
-       targa_header.y_origin = fgetLittleShort(fin);
-       targa_header.width = fgetLittleShort(fin);
-       targa_header.height = fgetLittleShort(fin);
+       targa_header.colormap_index = f[3] + f[4] * 256;
+       targa_header.colormap_length = f[5] + f[6] * 256;
+       targa_header.colormap_size = f[7];
+       targa_header.x_origin = f[8] + f[9] * 256;
+       targa_header.y_origin = f[10] + f[11] * 256;
+       targa_header.width = f[12] + f[13] * 256;
+       targa_header.height = f[14] + f[15] * 256;
        if (matchwidth && targa_header.width != matchwidth)
                return NULL;
        if (matchheight && targa_header.height != matchheight)
                return NULL;
-       targa_header.pixel_size = fgetc(fin);
-       targa_header.attributes = fgetc(fin);
+       targa_header.pixel_size = f[16];
+       targa_header.attributes = f[17];
 
-       if (targa_header.image_type!=2 
-               && targa_header.image_type!=10) 
+       if (targa_header.image_type != 2 && targa_header.image_type != 10)
                Host_Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
 
-       if (targa_header.colormap_type !=0 
-               || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
+       if (targa_header.colormap_type != 0     || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24))
                Host_Error ("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
 
        columns = targa_header.width;
        rows = targa_header.height;
        numPixels = columns * rows;
 
-       image_rgba = malloc (numPixels*4);
-       
+       image_rgba = qmalloc(numPixels*4);
+
+       fin = f + 18;
        if (targa_header.id_length != 0)
-               fseek(fin, targa_header.id_length, SEEK_CUR);  // skip TARGA image comment
+               fin += targa_header.id_length;  // skip TARGA image comment
        
-       if (targa_header.image_type==2) {  // Uncompressed, RGB images
-               for(row=rows-1; row>=0; row--) {
+       if (targa_header.image_type == 2)
+       {
+               // Uncompressed, RGB images
+               for(row = rows - 1;row >= 0;row--)
+               {
                        pixbuf = image_rgba + row*columns*4;
-                       for(column=0; column<columns; column++) {
-                               unsigned char red = 0,green = 0,blue = 0,alphabyte = 0;
-                               switch (targa_header.pixel_size) {
-                                       case 24:
-                                                       
-                                                       blue = getc(fin);
-                                                       green = getc(fin);
-                                                       red = getc(fin);
-                                                       *pixbuf++ = red;
-                                                       *pixbuf++ = green;
-                                                       *pixbuf++ = blue;
-                                                       *pixbuf++ = 255;
-                                                       break;
-                                       case 32:
-                                                       blue = getc(fin);
-                                                       green = getc(fin);
-                                                       red = getc(fin);
-                                                       alphabyte = getc(fin);
-                                                       *pixbuf++ = red;
-                                                       *pixbuf++ = green;
-                                                       *pixbuf++ = blue;
-                                                       *pixbuf++ = alphabyte;
-                                                       break;
+                       for(column = 0;column < columns;column++)
+                       {
+                               switch (targa_header.pixel_size)
+                               {
+                               case 24:
+                                       *pixbuf++ = fin[2];
+                                       *pixbuf++ = fin[1];
+                                       *pixbuf++ = fin[0];
+                                       *pixbuf++ = 255;
+                                       fin += 3;
+                                       break;
+                               case 32:
+                                       *pixbuf++ = fin[2];
+                                       *pixbuf++ = fin[1];
+                                       *pixbuf++ = fin[0];
+                                       *pixbuf++ = fin[3];
+                                       fin += 4;
+                                       break;
                                }
                        }
                }
        }
-       else if (targa_header.image_type==10) {   // Runlength encoded RGB images
-               unsigned char red = 0,green = 0,blue = 0,alphabyte = 0,packetHeader,packetSize,j;
-               for(row=rows-1; row>=0; row--) {
-                       pixbuf = image_rgba + row*columns*4;
-                       for(column=0; column<columns; ) {
-                               packetHeader=getc(fin);
+       else if (targa_header.image_type==10)
+       {
+               // Runlength encoded RGB images
+               unsigned char red = 0, green = 0, blue = 0, alphabyte = 0, packetHeader, packetSize, j;
+               for(row = rows - 1;row >= 0;row--)
+               {
+                       pixbuf = image_rgba + row * columns * 4;
+                       for(column = 0;column < columns;)
+                       {
+                               packetHeader = *fin++;
                                packetSize = 1 + (packetHeader & 0x7f);
-                               if (packetHeader & 0x80) {        // run-length packet
-                                       switch (targa_header.pixel_size) {
-                                               case 24:
-                                                               blue = getc(fin);
-                                                               green = getc(fin);
-                                                               red = getc(fin);
-                                                               alphabyte = 255;
-                                                               break;
-                                               case 32:
-                                                               blue = getc(fin);
-                                                               green = getc(fin);
-                                                               red = getc(fin);
-                                                               alphabyte = getc(fin);
-                                                               break;
+                               if (packetHeader & 0x80)
+                               {
+                                       // run-length packet
+                                       switch (targa_header.pixel_size)
+                                       {
+                                       case 24:
+                                               blue = *fin++;
+                                               green = *fin++;
+                                               red = *fin++;
+                                               alphabyte = 255;
+                                               break;
+                                       case 32:
+                                               blue = *fin++;
+                                               green = *fin++;
+                                               red = *fin++;
+                                               alphabyte = *fin++;
+                                               break;
                                        }
        
-                                       for(j=0;j<packetSize;j++) {
-                                               *pixbuf++=red;
-                                               *pixbuf++=green;
-                                               *pixbuf++=blue;
-                                               *pixbuf++=alphabyte;
+                                       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)
+                                               if (column == columns)
+                                               {
+                                                       // run spans across rows
+                                                       column = 0;
+                                                       if (row > 0)
                                                                row--;
                                                        else
                                                                goto breakOut;
-                                                       pixbuf = image_rgba + row*columns*4;
+                                                       pixbuf = image_rgba + row * columns * 4;
                                                }
                                        }
                                }
-                               else {                            // non run-length packet
-                                       for(j=0;j<packetSize;j++) {
-                                               switch (targa_header.pixel_size) {
-                                                       case 24:
-                                                                       blue = getc(fin);
-                                                                       green = getc(fin);
-                                                                       red = getc(fin);
-                                                                       *pixbuf++ = red;
-                                                                       *pixbuf++ = green;
-                                                                       *pixbuf++ = blue;
-                                                                       *pixbuf++ = 255;
-                                                                       break;
-                                                       case 32:
-                                                                       blue = getc(fin);
-                                                                       green = getc(fin);
-                                                                       red = getc(fin);
-                                                                       alphabyte = getc(fin);
-                                                                       *pixbuf++ = red;
-                                                                       *pixbuf++ = green;
-                                                                       *pixbuf++ = blue;
-                                                                       *pixbuf++ = alphabyte;
-                                                                       break;
+                               else
+                               {
+                                       // non run-length packet
+                                       for(j = 0;j < packetSize;j++)
+                                       {
+                                               switch (targa_header.pixel_size)
+                                               {
+                                               case 24:
+                                                       *pixbuf++ = fin[2];
+                                                       *pixbuf++ = fin[1];
+                                                       *pixbuf++ = fin[0];
+                                                       *pixbuf++ = 255;
+                                                       fin += 3;
+                                                       break;
+                                               case 32:
+                                                       *pixbuf++ = fin[2];
+                                                       *pixbuf++ = fin[1];
+                                                       *pixbuf++ = fin[0];
+                                                       *pixbuf++ = fin[3];
+                                                       fin += 4;
+                                                       break;
                                                }
                                                column++;
-                                               if (column==columns) { // pixel packet run spans across rows
-                                                       column=0;
-                                                       if (row>0)
+                                               if (column == columns)
+                                               {
+                                                       // pixel packet run spans across rows
+                                                       column = 0;
+                                                       if (row > 0)
                                                                row--;
                                                        else
                                                                goto breakOut;
-                                                       pixbuf = image_rgba + row*columns*4;
+                                                       pixbuf = image_rgba + row * columns * 4;
                                                }                                               
                                        }
                                }
@@ -371,9 +354,9 @@ byte* LoadTGA (FILE *fin, int matchwidth, int matchheight)
                }
        }
        
-       fclose(fin);
        image_width = columns;
        image_height = rows;
+       free(f);
        return image_rgba;
 }
 
@@ -382,28 +365,35 @@ byte* LoadTGA (FILE *fin, int matchwidth, int matchheight)
 LoadLMP
 ============
 */
-byte* LoadLMP (FILE *f, int matchwidth, int matchheight)
+byte* LoadLMP (byte *f, int matchwidth, int matchheight)
 {
        byte    *image_rgba;
        int             width, height;
 
        // parse the very complicated header *chuckle*
-       width = fgetLittleLong(f);
-       height = fgetLittleLong(f);
+       width = LittleLong(((int *)f)[0]);
+       height = LittleLong(((int *)f)[1]);
        if ((unsigned) width > 4096 || (unsigned) height > 4096)
+       {
+               qfree(f);
                Host_Error("LoadLMP: invalid size\n");
+       }
        if (matchwidth && width != matchwidth)
+       {
+               qfree(f);
                return NULL;
+       }
        if (matchheight && height != matchheight)
+       {
+               qfree(f);
                return NULL;
+       }
 
-       image_rgba = malloc(width*height*4);
-       fread(image_rgba + width*height*3, 1, width*height, f);
-       fclose(f);
-
-       Image_Copy8bitRGBA(image_rgba + width*height*3, image_rgba, width*height, d_8to24table);
+       image_rgba = qmalloc(width*height*4);
+       Image_Copy8bitRGBA(f + 8, image_rgba, width*height, d_8to24table);
        image_width = width;
        image_height = height;
+       qfree(f);
        return image_rgba;
 }
 
@@ -426,41 +416,36 @@ void Image_StripImageExtension (char *in, char *out)
 
 byte* loadimagepixels (char* filename, qboolean complain, int matchwidth, int matchheight)
 {
-       FILE    *f;
+       byte    *f;
        char    basename[256], name[256];
-       byte    *image_rgba, *c;
+       byte    *c;
        Image_StripImageExtension(filename, basename); // strip .tga, .pcx and .lmp extensions to allow replacement by other types
        // replace *'s with #, so commandline utils don't get confused when dealing with the external files
        for (c = basename;*c;c++)
                if (*c == '*')
                        *c = '#';
        sprintf (name, "textures/%s.tga", basename);
-       COM_FOpenFile (name, &f, true);
+       f = COM_LoadMallocFile(name, true);
        if (f)
                return LoadTGA (f, matchwidth, matchheight);
        sprintf (name, "textures/%s.pcx", basename);
-       COM_FOpenFile (name, &f, true);
+       f = COM_LoadMallocFile(name, true);
        if (f)
                return LoadPCX (f, matchwidth, matchheight);
        sprintf (name, "%s.tga", basename);
-       COM_FOpenFile (name, &f, true);
+       f = COM_LoadMallocFile(name, true);
        if (f)
                return LoadTGA (f, matchwidth, matchheight);
        sprintf (name, "%s.pcx", basename);
-       COM_FOpenFile (name, &f, true);
+       f = COM_LoadMallocFile(name, true);
        if (f)
                return LoadPCX (f, matchwidth, matchheight);
        sprintf (name, "%s.lmp", basename);
-       COM_FOpenFile (name, &f, true);
+       f = COM_LoadMallocFile(name, true);
        if (f)
                return LoadLMP (f, matchwidth, matchheight);
-       if ((image_rgba = W_GetTexture(basename, matchwidth, matchheight)))
-               return image_rgba;
-       COM_StripExtension(filename, basename); // do it again with a * this time
-       if ((image_rgba = W_GetTexture(basename, matchwidth, matchheight)))
-               return image_rgba;
        if (complain)
-               Con_Printf ("Couldn't load %s.tga or .pcx\n", filename);
+               Con_Printf ("Couldn't load %s.tga, .pcx, .lmp\n", filename);
        return NULL;
 }
 
@@ -490,53 +475,83 @@ byte* loadimagepixelsmask (char* filename, qboolean complain, int matchwidth, in
                return data; // some transparency
        else
        {
-               free(data);
+               qfree(data);
                return NULL; // all opaque
        }
 }
 
-int loadtextureimage (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap)
+rtexture_t *loadtextureimage (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache)
 {
-       int texnum;
        byte *data;
+       rtexture_t *rt;
        if (!(data = loadimagepixels (filename, complain, matchwidth, matchheight)))
                return 0;
-       texnum = GL_LoadTexture (filename, image_width, image_height, data, mipmap, true, 4);
-       free(data);
-       return texnum;
+       rt = R_LoadTexture (filename, image_width, image_height, data, TEXF_ALPHA | TEXF_RGBA | (mipmap ? TEXF_MIPMAP : 0) | (mipmap ? TEXF_PRECACHE : 0));
+       qfree(data);
+       return rt;
 }
 
-int loadtextureimagemask (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap)
+rtexture_t *loadtextureimagemask (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache)
 {
-       int texnum;
        byte *data;
+       rtexture_t *rt;
        if (!(data = loadimagepixelsmask (filename, complain, matchwidth, matchheight)))
                return 0;
-       texnum = GL_LoadTexture (filename, image_width, image_height, data, mipmap, true, 4);
-       free(data);
-       return texnum;
+       rt = R_LoadTexture (filename, image_width, image_height, data, TEXF_ALPHA | TEXF_RGBA | (mipmap ? TEXF_MIPMAP : 0) | (mipmap ? TEXF_PRECACHE : 0));
+       qfree(data);
+       return rt;
 }
 
-int image_masktexnum;
-int loadtextureimagewithmask (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap)
+rtexture_t *image_masktex;
+rtexture_t *loadtextureimagewithmask (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache)
 {
-       int texnum, count;
+       int count;
        byte *data;
        char *filename2;
-       image_masktexnum = 0;
+       rtexture_t *rt;
+       image_masktex = NULL;
        if (!(data = loadimagepixels (filename, complain, matchwidth, matchheight)))
                return 0;
-       texnum = GL_LoadTexture (filename, image_width, image_height, data, mipmap, true, 4);
+       rt = R_LoadTexture (filename, image_width, image_height, data, TEXF_ALPHA | TEXF_RGBA | (mipmap ? TEXF_MIPMAP : 0) | (mipmap ? TEXF_PRECACHE : 0));
        count = image_makemask(data, data, image_width * image_height);
        if (count)
        {
-               filename2 = malloc(strlen(filename) + 6);
+               filename2 = qmalloc(strlen(filename) + 6);
                sprintf(filename2, "%s_mask", filename);
-               image_masktexnum = GL_LoadTexture (filename2, image_width, image_height, data, mipmap, true, 4);
-               free(filename2);
+               image_masktex = R_LoadTexture (filename2, image_width, image_height, data, TEXF_ALPHA | TEXF_RGBA | (mipmap ? TEXF_MIPMAP : 0) | (mipmap ? TEXF_PRECACHE : 0));
+               qfree(filename2);
        }
-       free(data);
-       return texnum;
+       qfree(data);
+       return rt;
+}
+
+void Image_WriteTGARGB_preflipped (char *filename, int width, int height, byte *data)
+{
+       byte *buffer, *in, *out, *end;
+
+       buffer = qmalloc(width*height*3 + 18);
+
+       memset (buffer, 0, 18);
+       buffer[2] = 2;          // uncompressed type
+       buffer[12] = (width >> 0) & 0xFF;
+       buffer[13] = (width >> 8) & 0xFF;
+       buffer[14] = (height >> 0) & 0xFF;
+       buffer[15] = (height >> 8) & 0xFF;
+       buffer[16] = 24;        // pixel size
+
+       // swap rgb to bgr
+       in = data;
+       out = buffer + 18;
+       end = in + width*height*3;
+       for (;in < end;in += 3)
+       {
+               *out++ = in[2];
+               *out++ = in[1];
+               *out++ = in[0];
+       }
+       COM_WriteFile (filename, buffer, width*height*3 + 18 );
+
+       qfree(buffer);
 }
 
 void Image_WriteTGARGB (char *filename, int width, int height, byte *data)
@@ -544,7 +559,7 @@ void Image_WriteTGARGB (char *filename, int width, int height, byte *data)
        int y;
        byte *buffer, *in, *out, *end;
 
-       buffer = malloc(width*height*3 + 18);
+       buffer = qmalloc(width*height*3 + 18);
 
        memset (buffer, 0, 18);
        buffer[2] = 2;          // uncompressed type
@@ -569,7 +584,7 @@ void Image_WriteTGARGB (char *filename, int width, int height, byte *data)
        }
        COM_WriteFile (filename, buffer, width*height*3 + 18 );
 
-       free(buffer);
+       qfree(buffer);
 }
 
 void Image_WriteTGARGBA (char *filename, int width, int height, byte *data)
@@ -577,7 +592,7 @@ void Image_WriteTGARGBA (char *filename, int width, int height, byte *data)
        int y;
        byte *buffer, *in, *out, *end;
 
-       buffer = malloc(width*height*4 + 18);
+       buffer = qmalloc(width*height*4 + 18);
 
        memset (buffer, 0, 18);
        buffer[2] = 2;          // uncompressed type
@@ -603,5 +618,25 @@ void Image_WriteTGARGBA (char *filename, int width, int height, byte *data)
        }
        COM_WriteFile (filename, buffer, width*height*4 + 18 );
 
-       free(buffer);
+       qfree(buffer);
+}
+
+qboolean Image_CheckAlpha(byte *data, int size, qboolean rgba)
+{
+       byte *end;
+       if (rgba)
+       {
+               // check alpha bytes
+               for (end = data + size * 4, data += 3;data < end;data += 4)
+                       if (*data < 255)
+                               return 1;
+       }
+       else
+       {
+               // color 255 is transparent
+               for (end = data + size;data < end;data++)
+                       if (*data == 255)
+                               return 1;
+       }
+       return 0;
 }