]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - image.c
rewrote memory system entirely (hunk, cache, and zone are gone, memory pools replaced...
[xonotic/darkplaces.git] / image.c
diff --git a/image.c b/image.c
index a0bd89a3bc26cd5ea24ee43bd43d1dd7dcea6d03..dbad08ff5b69231a6e8255e1faafe393b8efaa11 100644 (file)
--- a/image.c
+++ b/image.c
@@ -4,6 +4,18 @@
 int            image_width;
 int            image_height;
 
+void Image_GammaRemapRGB(byte *in, byte *out, int pixels, byte *gammar, byte *gammag, byte *gammab)
+{
+       while (pixels--)
+       {
+               out[0] = gammar[in[0]];
+               out[1] = gammag[in[1]];
+               out[2] = gammab[in[2]];
+               in += 3;
+               out += 3;
+       }
+}
+
 // note: pal must be 32bit color
 void Image_Copy8bitRGBA(byte *in, byte *out, int pixels, int *pal)
 {
@@ -42,20 +54,6 @@ void Image_Copy8bitRGBA(byte *in, byte *out, int pixels, int *pal)
                iout[0] = pal[in[0]];
 }
 
-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] ;
-               in += 4;
-               out += 4;
-       }
-}
-
-
 /*
 =================================================================
 
@@ -78,7 +76,6 @@ typedef struct
     unsigned short     bytes_per_line;
     unsigned short     palette_type;
     char       filler[58];
-    unsigned   data;                   // unbounded
 } pcx_t;
 
 /*
@@ -86,91 +83,98 @@ 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, *enddata;
+       int             x, y, x2, dataByte;
 
-//
-// parse the PCX file
-//
-       fread (&pcxbuf, 1, sizeof(pcxbuf), f);
+       if (loadsize < sizeof(pcx) + 768)
+       {
+               Con_Printf ("Bad pcx file\n");
+               return NULL;
+       }
 
-       pcx = &pcxbuf;
+       fin = f;
 
-       // 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);
+       memcpy(&pcx, fin, sizeof(pcx));
+       fin += sizeof(pcx);
 
-       if (pcx->manufacturer != 0x0a || pcx->version != 5 || pcx->encoding != 1 || pcx->bits_per_pixel != 8 || pcx->xmax > 320 || pcx->ymax > 256)
+       // 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)
        {
                Con_Printf ("Bad pcx file\n");
                return NULL;
        }
 
-       if (matchwidth && (pcx->xmax+1) != matchwidth)
+       if (matchwidth && (pcx.xmax+1) != matchwidth)
+       {
                return NULL;
-       if (matchheight && (pcx->ymax+1) != matchheight)
+       }
+       if (matchheight && (pcx.ymax+1) != matchheight)
+       {
                return NULL;
+       }
 
-       // seek to palette
-       fseek (f, -768, SEEK_END);
-       fread (palette, 1, 768, f);
+       image_width = pcx.xmax+1;
+       image_height = pcx.ymax+1;
 
-       fseek (f, sizeof(pcxbuf) - 4, SEEK_SET);
+       palette = f + loadsize - 768;
 
-       count = (pcx->xmax+1) * (pcx->ymax+1);
-       image_rgba = malloc( count * 4);
+       image_rgba = Mem_Alloc(tempmempool, image_width*image_height*4);
+       if (!image_rgba)
+       {
+               Con_Printf("LoadPCX: not enough memory for %i by %i image\n", image_width, image_height);
+               return NULL;
+       }
+       pbuf = image_rgba + image_width*image_height*3;
+       enddata = palette;
 
-       for (y=0 ; y<=pcx->ymax ; y++)
+       for (y = 0;y < image_height && fin < enddata;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 && fin < enddata;)
                {
-                       dataByte = fgetc(f);
-
-                       if((dataByte & 0xC0) == 0xC0)
+                       dataByte = *fin++;
+                       if(dataByte >= 0xC0)
                        {
-                               runLength = dataByte & 0x3F;
-                               dataByte = fgetc(f);
-                               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;
-                                       }
-                               }
+                               if (fin >= enddata)
+                                       break;
+                               x2 = x + (dataByte & 0x3F);
+                               dataByte = *fin++;
+                               if (x2 > image_width)
+                                       x2 = image_width; // technically an error
+                               while(x < x2)
+                                       a[x++] = 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[x++] = dataByte;
                }
+               while(x < image_width)
+                       a[x++] = 0;
+       }
+
+       a = image_rgba;
+       b = pbuf;
+
+       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;
        }
-       fclose(f);
-       image_width = pcx->xmax+1;
-       image_height = pcx->ymax+1;
+
        return image_rgba;
 }
 
@@ -182,38 +186,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,157 +204,191 @@ 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);
-       
-       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);
+       int columns, rows, row, column;
+       byte *pixbuf, *image_rgba, *fin, *enddata;
+
+       if (loadsize < 18+3)
+               return NULL;
+       targa_header.id_length = f[0];
+       targa_header.colormap_type = f[1];
+       targa_header.image_type = f[2];
+
+       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) 
-               Host_Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
+       if (targa_header.image_type != 2 && targa_header.image_type != 10)
+       {
+               Con_Printf ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
+               return NULL;
+       }
 
-       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");
+       if (targa_header.colormap_type != 0     || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24))
+       {
+               Con_Printf ("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
+               return NULL;
+       }
+
+       enddata = f + loadsize;
 
        columns = targa_header.width;
        rows = targa_header.height;
-       numPixels = columns * rows;
 
-       image_rgba = malloc (numPixels*4);
-       
+       image_rgba = Mem_Alloc(tempmempool, columns * rows * 4);
+       if (!image_rgba)
+       {
+               Con_Printf ("LoadTGA: not enough memory for %i by %i image\n", columns, rows);
+               return NULL;
+       }
+
+       fin = f + 18;
        if (targa_header.id_length != 0)
-               fseek(fin, targa_header.id_length, SEEK_CUR);  // skip TARGA image comment
-       
-       if (targa_header.image_type==2) {  // Uncompressed, RGB images
-               for(row=rows-1; row>=0; row--) {
+               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--)
+               {
                        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:
+                                       if (fin + 3 > enddata)
+                                               break;
+                                       *pixbuf++ = fin[2];
+                                       *pixbuf++ = fin[1];
+                                       *pixbuf++ = fin[0];
+                                       *pixbuf++ = 255;
+                                       fin += 3;
+                                       break;
+                               case 32:
+                                       if (fin + 4 > enddata)
+                                               break;
+                                       *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;)
+                       {
+                               if (fin >= enddata)
+                                       goto outofdata;
+                               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:
+                                               if (fin + 3 > enddata)
+                                                       goto outofdata;
+                                               blue = *fin++;
+                                               green = *fin++;
+                                               red = *fin++;
+                                               alphabyte = 255;
+                                               break;
+                                       case 32:
+                                               if (fin + 4 > enddata)
+                                                       goto outofdata;
+                                               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:
+                                                       if (fin + 3 > enddata)
+                                                               goto outofdata;
+                                                       *pixbuf++ = fin[2];
+                                                       *pixbuf++ = fin[1];
+                                                       *pixbuf++ = fin[0];
+                                                       *pixbuf++ = 255;
+                                                       fin += 3;
+                                                       break;
+                                               case 32:
+                                                       if (fin + 4 > enddata)
+                                                               goto outofdata;
+                                                       *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;
+                                               }
                                        }
                                }
                        }
                        breakOut:;
                }
        }
-       
-       fclose(fin);
+outofdata:;
+
        image_width = columns;
        image_height = rows;
        return image_rgba;
@@ -382,68 +399,115 @@ 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;
 
+       if (loadsize < 9)
+       {
+               Con_Printf("LoadLMP: invalid LMP file\n");
+               return NULL;
+       }
+
        // parse the very complicated header *chuckle*
-       width = fgetLittleLong(f);
-       height = fgetLittleLong(f);
+       width = f[0] + f[1] * 256 + f[2] * 65536 + f[3] * 16777216;
+       height = f[4] + f[5] * 256 + f[6] * 65536 + f[7] * 16777216;
        if ((unsigned) width > 4096 || (unsigned) height > 4096)
-               Host_Error("LoadLMP: invalid size\n");
-       if (matchwidth && width != matchwidth)
+       {
+               Con_Printf("LoadLMP: invalid size\n");
                return NULL;
-       if (matchheight && height != matchheight)
+       }
+       if ((matchwidth && width != matchwidth) || (matchheight && height != matchheight))
                return NULL;
 
-       image_rgba = malloc(width*height*4);
-       fread(image_rgba + width*height*3, 1, width*height, f);
-       fclose(f);
+       if (loadsize < 8 + width * height)
+       {
+               Con_Printf("LoadLMP: invalid LMP file\n");
+               return NULL;
+       }
 
-       Image_Copy8bitRGBA(image_rgba + width*height*3, image_rgba, width*height, d_8to24table);
        image_width = width;
        image_height = height;
+
+       image_rgba = Mem_Alloc(tempmempool, image_width * image_height * 4);
+       if (!image_rgba)
+       {
+               Con_Printf("LoadLMP: not enough memory for %i by %i image\n", image_width, image_height);
+               return NULL;
+       }
+       Image_Copy8bitRGBA(f + 8, image_rgba, image_width * image_height, d_8to24table);
        return image_rgba;
 }
 
+void Image_StripImageExtension (char *in, char *out)
+{
+       char *end, *temp;
+       end = in + strlen(in);
+       if ((end - in) >= 4)
+       {
+               temp = end - 4;
+               if (strcmp(temp, ".tga") == 0 || strcmp(temp, ".pcx") == 0 || strcmp(temp, ".lmp") == 0)
+                       end = temp;
+               while (in < end)
+                       *out++ = *in++;
+               *out++ = 0;
+       }
+       else
+               strcpy(out, in);
+}
+
 byte* loadimagepixels (char* filename, qboolean complain, int matchwidth, int matchheight)
 {
-       FILE    *f;
-       char    basename[128], name[128];
-       byte    *image_rgba, *c;
-       COM_StripExtension(filename, basename); // strip the extension to allow TGA skins on Q2 models despite the .pcx in the skin name
+       byte    *f, *data;
+       char    basename[256], name[256], *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_LoadFile(name, true);
        if (f)
-               return LoadTGA (f, matchwidth, matchheight);
+       {
+               data = LoadTGA (f, matchwidth, matchheight);
+               Mem_Free(f);
+               return data;
+       }
        sprintf (name, "textures/%s.pcx", basename);
-       COM_FOpenFile (name, &f, true);
+       f = COM_LoadFile(name, true);
        if (f)
-               return LoadPCX (f, matchwidth, matchheight);
+       {
+               data = LoadPCX (f, matchwidth, matchheight);
+               Mem_Free(f);
+               return data;
+       }
        sprintf (name, "%s.tga", basename);
-       COM_FOpenFile (name, &f, true);
+       f = COM_LoadFile(name, true);
        if (f)
-               return LoadTGA (f, matchwidth, matchheight);
+       {
+               data = LoadTGA (f, matchwidth, matchheight);
+               Mem_Free(f);
+               return data;
+       }
        sprintf (name, "%s.pcx", basename);
-       COM_FOpenFile (name, &f, true);
+       f = COM_LoadFile(name, true);
        if (f)
-               return LoadPCX (f, matchwidth, matchheight);
+       {
+               data = LoadPCX (f, matchwidth, matchheight);
+               Mem_Free(f);
+               return data;
+       }
        sprintf (name, "%s.lmp", basename);
-       COM_FOpenFile (name, &f, true);
+       f = COM_LoadFile(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;
+       {
+               data = LoadLMP (f, matchwidth, matchheight);
+               Mem_Free(f);
+               return data;
+       }
        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;
 }
 
@@ -473,60 +537,61 @@ byte* loadimagepixelsmask (char* filename, qboolean complain, int matchwidth, in
                return data; // some transparency
        else
        {
-               free(data);
+               Mem_Free(data);
                return NULL; // all opaque
        }
 }
 
-int loadtextureimage (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap)
+rtexture_t *loadtextureimage (rtexturepool_t *pool, 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 (pool, filename, image_width, image_height, data, TEXTYPE_RGBA, TEXF_ALPHA | (mipmap ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0));
+       Mem_Free(data);
+       return rt;
 }
 
-int loadtextureimagemask (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap)
+rtexture_t *loadtextureimagemask (rtexturepool_t *pool, 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 (pool, filename, image_width, image_height, data, TEXTYPE_RGBA, TEXF_ALPHA | (mipmap ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0));
+       Mem_Free(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 (rtexturepool_t *pool, 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 (pool, filename, image_width, image_height, data, TEXTYPE_RGBA, TEXF_ALPHA | (mipmap ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0));
        count = image_makemask(data, data, image_width * image_height);
        if (count)
        {
-               filename2 = malloc(strlen(filename) + 6);
+               filename2 = Mem_Alloc(tempmempool, 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 (pool, filename2, image_width, image_height, data, TEXTYPE_RGBA, TEXF_ALPHA | (mipmap ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0));
+               Mem_Free(filename2);
        }
-       free(data);
-       return texnum;
+       Mem_Free(data);
+       return rt;
 }
 
-void Image_WriteTGARGB (char *filename, int width, int height, byte *data)
+void Image_WriteTGARGB_preflipped (char *filename, int width, int height, byte *data)
 {
        byte *buffer, *in, *out, *end;
 
-       buffer = malloc(width*height*3 + 18);
+       buffer = Mem_Alloc(tempmempool, width*height*3 + 18);
 
        memset (buffer, 0, 18);
        buffer[2] = 2;          // uncompressed type
@@ -538,15 +603,102 @@ void Image_WriteTGARGB (char *filename, int width, int height, byte *data)
 
        // swap rgb to bgr
        in = data;
-       end = in + width*height*3;
        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, glwidth*glheight*3 + 18 );
+       COM_WriteFile (filename, buffer, width*height*3 + 18 );
+
+       Mem_Free(buffer);
+}
 
-       free(buffer);
+void Image_WriteTGARGB (char *filename, int width, int height, byte *data)
+{
+       int y;
+       byte *buffer, *in, *out, *end;
+
+       buffer = Mem_Alloc(tempmempool, 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 and flip upside down
+       out = buffer + 18;
+       for (y = height - 1;y >= 0;y--)
+       {
+               in = data + y * width * 3;
+               end = in + width * 3;
+               for (;in < end;in += 3)
+               {
+                       *out++ = in[2];
+                       *out++ = in[1];
+                       *out++ = in[0];
+               }
+       }
+       COM_WriteFile (filename, buffer, width*height*3 + 18 );
+
+       Mem_Free(buffer);
+}
+
+void Image_WriteTGARGBA (char *filename, int width, int height, byte *data)
+{
+       int y;
+       byte *buffer, *in, *out, *end;
+
+       buffer = Mem_Alloc(tempmempool, width*height*4 + 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] = 32;        // pixel size
+
+       // swap rgba to bgra and flip upside down
+       out = buffer + 18;
+       for (y = height - 1;y >= 0;y--)
+       {
+               in = data + y * width * 4;
+               end = in + width * 4;
+               for (;in < end;in += 4)
+               {
+                       *out++ = in[2];
+                       *out++ = in[1];
+                       *out++ = in[0];
+                       *out++ = in[3];
+               }
+       }
+       COM_WriteFile (filename, buffer, width*height*4 + 18 );
+
+       Mem_Free(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;
 }