+ rt = R_LoadTexture2D(pool, filename, image_width, image_height, data, TEXTYPE_BGRA, flags, NULL);
+ Mem_Free(data);
+ return rt;
+}
+
+int fixtransparentpixels(unsigned char *data, int w, int h)
+{
+ int const FIXTRANS_NEEDED = 1;
+ int const FIXTRANS_HAS_L = 2;
+ int const FIXTRANS_HAS_R = 4;
+ int const FIXTRANS_HAS_U = 8;
+ int const FIXTRANS_HAS_D = 16;
+ int const FIXTRANS_FIXED = 32;
+ unsigned char *fixMask = Mem_Alloc(tempmempool, w * h);
+ int fixPixels = 0;
+ int changedPixels = 0;
+ int x, y;
+
+#define FIXTRANS_PIXEL (y*w+x)
+#define FIXTRANS_PIXEL_U (((y+h-1)%h)*w+x)
+#define FIXTRANS_PIXEL_D (((y+1)%h)*w+x)
+#define FIXTRANS_PIXEL_L (y*w+((x+w-1)%w))
+#define FIXTRANS_PIXEL_R (y*w+((x+1)%w))
+
+ memset(fixMask, 0, w * h);
+ for(y = 0; y < h; ++y)
+ for(x = 0; x < w; ++x)
+ {
+ if(data[FIXTRANS_PIXEL * 4 + 3] == 0)
+ {
+ fixMask[FIXTRANS_PIXEL] |= FIXTRANS_NEEDED;
+ ++fixPixels;
+ }
+ else
+ {
+ fixMask[FIXTRANS_PIXEL_D] |= FIXTRANS_HAS_U;
+ fixMask[FIXTRANS_PIXEL_U] |= FIXTRANS_HAS_D;
+ fixMask[FIXTRANS_PIXEL_R] |= FIXTRANS_HAS_L;
+ fixMask[FIXTRANS_PIXEL_L] |= FIXTRANS_HAS_R;
+ }
+ }
+ if(fixPixels == w * h)
+ return 0; // sorry, can't do anything about this
+ while(fixPixels)
+ {
+ for(y = 0; y < h; ++y)
+ for(x = 0; x < w; ++x)
+ if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_NEEDED)
+ {
+ unsigned int sumR = 0, sumG = 0, sumB = 0, sumA = 0, sumRA = 0, sumGA = 0, sumBA = 0, cnt = 0;
+ unsigned char r, g, b, a, r0, g0, b0;
+ if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_U)
+ {
+ r = data[FIXTRANS_PIXEL_U * 4 + 2];
+ g = data[FIXTRANS_PIXEL_U * 4 + 1];
+ b = data[FIXTRANS_PIXEL_U * 4 + 0];
+ a = data[FIXTRANS_PIXEL_U * 4 + 3];
+ sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
+ }
+ if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_D)
+ {
+ r = data[FIXTRANS_PIXEL_D * 4 + 2];
+ g = data[FIXTRANS_PIXEL_D * 4 + 1];
+ b = data[FIXTRANS_PIXEL_D * 4 + 0];
+ a = data[FIXTRANS_PIXEL_D * 4 + 3];
+ sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
+ }
+ if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_L)
+ {
+ r = data[FIXTRANS_PIXEL_L * 4 + 2];
+ g = data[FIXTRANS_PIXEL_L * 4 + 1];
+ b = data[FIXTRANS_PIXEL_L * 4 + 0];
+ a = data[FIXTRANS_PIXEL_L * 4 + 3];
+ sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
+ }
+ if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_R)
+ {
+ r = data[FIXTRANS_PIXEL_R * 4 + 2];
+ g = data[FIXTRANS_PIXEL_R * 4 + 1];
+ b = data[FIXTRANS_PIXEL_R * 4 + 0];
+ a = data[FIXTRANS_PIXEL_R * 4 + 3];
+ sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
+ }
+ if(!cnt)
+ continue;
+ r0 = data[FIXTRANS_PIXEL * 4 + 2];
+ g0 = data[FIXTRANS_PIXEL * 4 + 1];
+ b0 = data[FIXTRANS_PIXEL * 4 + 0];
+ if(sumA)
+ {
+ // there is a surrounding non-alpha pixel
+ r = (sumRA + sumA / 2) / sumA;
+ g = (sumGA + sumA / 2) / sumA;
+ b = (sumBA + sumA / 2) / sumA;
+ }
+ else
+ {
+ // need to use a "regular" average
+ r = (sumR + cnt / 2) / cnt;
+ g = (sumG + cnt / 2) / cnt;
+ b = (sumB + cnt / 2) / cnt;
+ }
+ if(r != r0 || g != g0 || b != b0)
+ ++changedPixels;
+ data[FIXTRANS_PIXEL * 4 + 2] = r;
+ data[FIXTRANS_PIXEL * 4 + 1] = g;
+ data[FIXTRANS_PIXEL * 4 + 0] = b;
+ fixMask[FIXTRANS_PIXEL] |= FIXTRANS_FIXED;
+ }
+ for(y = 0; y < h; ++y)
+ for(x = 0; x < w; ++x)
+ if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_FIXED)
+ {
+ fixMask[FIXTRANS_PIXEL] &= ~(FIXTRANS_NEEDED | FIXTRANS_FIXED);
+ fixMask[FIXTRANS_PIXEL_D] |= FIXTRANS_HAS_U;
+ fixMask[FIXTRANS_PIXEL_U] |= FIXTRANS_HAS_D;
+ fixMask[FIXTRANS_PIXEL_R] |= FIXTRANS_HAS_L;
+ fixMask[FIXTRANS_PIXEL_L] |= FIXTRANS_HAS_R;
+ --fixPixels;
+ }
+ }
+ return changedPixels;
+}
+
+void Image_FixTransparentPixels_f(void)
+{
+ const char *filename, *filename_pattern;
+ fssearch_t *search;
+ int i, n;
+ char outfilename[MAX_QPATH], buf[MAX_QPATH];
+ unsigned char *data;
+ if(Cmd_Argc() != 2)
+ {
+ Con_Printf("Usage: %s imagefile\n", Cmd_Argv(0));
+ return;
+ }
+ filename_pattern = Cmd_Argv(1);
+ search = FS_Search(filename_pattern, true, true);
+ if(!search)
+ return;
+ for(i = 0; i < search->numfilenames; ++i)
+ {
+ filename = search->filenames[i];
+ Con_Printf("Processing %s... ", filename);
+ Image_StripImageExtension(filename, buf, sizeof(buf));
+ dpsnprintf(outfilename, sizeof(outfilename), "fixtrans/%s.tga", buf);
+ if(!(data = loadimagepixelsbgra(filename, true, false)))
+ return;
+ if((n = fixtransparentpixels(data, image_width, image_height)))
+ {
+ Image_WriteTGABGRA(outfilename, image_width, image_height, data);
+ Con_Printf("%s written (%d pixels changed).\n", outfilename, n);
+ }
+ else
+ Con_Printf("unchanged.\n");
+ Mem_Free(data);
+ }
+}
+
+qboolean Image_WriteTGABGR_preflipped (const char *filename, int width, int height, const unsigned char *data, unsigned char *buffer)
+{
+ qboolean ret;
+
+ 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
+ memcpy(buffer + 18, data, width*height*3);
+ ret = FS_WriteFile (filename, buffer, width*height*3 + 18 );
+
+ return ret;
+}
+
+void Image_WriteTGABGRA (const char *filename, int width, int height, const unsigned char *data)
+{
+ int y;
+ unsigned char *buffer, *out;
+ const unsigned char *in, *end;
+
+ buffer = (unsigned char *)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;
+
+ for (y = 3;y < width*height*4;y += 4)
+ if (data[y] < 255)
+ break;
+
+ if (y < width*height*4)
+ {
+ // save the alpha channel
+ buffer[16] = 32; // pixel size
+ buffer[17] = 8; // 8 bits of alpha
+
+ // flip upside down
+ out = buffer + 18;
+ for (y = height - 1;y >= 0;y--)
+ {
+ memcpy(out, data + y * width * 4, width * 4);
+ out += width*4;
+ }
+ }
+ else
+ {
+ // save only the color channels
+ buffer[16] = 24; // pixel size
+ buffer[17] = 0; // 8 bits of alpha
+
+ // truncate bgra to bgr 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[0];
+ *out++ = in[1];
+ *out++ = in[2];
+ }
+ }
+ }
+ FS_WriteFile (filename, buffer, out - buffer);
+
+ Mem_Free(buffer);
+}
+
+static void Image_Resample32LerpLine (const unsigned char *in, unsigned char *out, int inwidth, int outwidth)
+{
+ int j, xi, oldx = 0, f, fstep, endx, lerp;
+ fstep = (int) (inwidth*65536.0f/outwidth);
+ endx = (inwidth-1);
+ for (j = 0,f = 0;j < outwidth;j++, f += fstep)
+ {
+ xi = f >> 16;
+ if (xi != oldx)
+ {
+ in += (xi - oldx) * 4;
+ oldx = xi;
+ }
+ if (xi < endx)
+ {
+ lerp = f & 0xFFFF;
+ *out++ = (unsigned char) ((((in[4] - in[0]) * lerp) >> 16) + in[0]);
+ *out++ = (unsigned char) ((((in[5] - in[1]) * lerp) >> 16) + in[1]);
+ *out++ = (unsigned char) ((((in[6] - in[2]) * lerp) >> 16) + in[2]);
+ *out++ = (unsigned char) ((((in[7] - in[3]) * lerp) >> 16) + in[3]);
+ }
+ else // last pixel of the line has no pixel to lerp to
+ {
+ *out++ = in[0];
+ *out++ = in[1];
+ *out++ = in[2];
+ *out++ = in[3];
+ }
+ }
+}
+
+#define LERPBYTE(i) r = resamplerow1[i];out[i] = (unsigned char) ((((resamplerow2[i] - r) * lerp) >> 16) + r)
+void Image_Resample32Lerp(const void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight)
+{
+ int i, j, r, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth4 = inwidth*4, outwidth4 = outwidth*4;
+ unsigned char *out;
+ const unsigned char *inrow;
+ unsigned char *resamplerow1;
+ unsigned char *resamplerow2;
+ out = (unsigned char *)outdata;
+ fstep = (int) (inheight*65536.0f/outheight);
+
+ resamplerow1 = (unsigned char *)Mem_Alloc(tempmempool, outwidth*4*2);
+ resamplerow2 = resamplerow1 + outwidth*4;
+
+ inrow = (const unsigned char *)indata;
+ oldy = 0;
+ Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth);
+ Image_Resample32LerpLine (inrow + inwidth4, resamplerow2, inwidth, outwidth);
+ for (i = 0, f = 0;i < outheight;i++,f += fstep)
+ {
+ yi = f >> 16;
+ if (yi < endy)
+ {
+ lerp = f & 0xFFFF;
+ if (yi != oldy)
+ {
+ inrow = (unsigned char *)indata + inwidth4*yi;
+ if (yi == oldy+1)
+ memcpy(resamplerow1, resamplerow2, outwidth4);
+ else
+ Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth);
+ Image_Resample32LerpLine (inrow + inwidth4, resamplerow2, inwidth, outwidth);
+ oldy = yi;
+ }
+ j = outwidth - 4;
+ while(j >= 0)
+ {
+ LERPBYTE( 0);
+ LERPBYTE( 1);
+ LERPBYTE( 2);
+ LERPBYTE( 3);
+ LERPBYTE( 4);
+ LERPBYTE( 5);
+ LERPBYTE( 6);
+ LERPBYTE( 7);
+ LERPBYTE( 8);
+ LERPBYTE( 9);
+ LERPBYTE(10);
+ LERPBYTE(11);
+ LERPBYTE(12);
+ LERPBYTE(13);
+ LERPBYTE(14);
+ LERPBYTE(15);
+ out += 16;
+ resamplerow1 += 16;
+ resamplerow2 += 16;
+ j -= 4;
+ }
+ if (j & 2)
+ {
+ LERPBYTE( 0);
+ LERPBYTE( 1);
+ LERPBYTE( 2);
+ LERPBYTE( 3);
+ LERPBYTE( 4);
+ LERPBYTE( 5);
+ LERPBYTE( 6);
+ LERPBYTE( 7);
+ out += 8;
+ resamplerow1 += 8;
+ resamplerow2 += 8;
+ }
+ if (j & 1)
+ {
+ LERPBYTE( 0);
+ LERPBYTE( 1);
+ LERPBYTE( 2);
+ LERPBYTE( 3);
+ out += 4;
+ resamplerow1 += 4;
+ resamplerow2 += 4;
+ }
+ resamplerow1 -= outwidth4;
+ resamplerow2 -= outwidth4;
+ }
+ else
+ {
+ if (yi != oldy)
+ {
+ inrow = (unsigned char *)indata + inwidth4*yi;
+ if (yi == oldy+1)
+ memcpy(resamplerow1, resamplerow2, outwidth4);
+ else
+ Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth);
+ oldy = yi;
+ }
+ memcpy(out, resamplerow1, outwidth4);
+ }
+ }
+
+ Mem_Free(resamplerow1);
+ resamplerow1 = NULL;
+ resamplerow2 = NULL;
+}
+
+void Image_Resample32Nolerp(const void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight)
+{
+ int i, j;
+ unsigned frac, fracstep;
+ // relies on int being 4 bytes
+ int *inrow, *out;
+ out = (int *)outdata;
+
+ fracstep = inwidth*0x10000/outwidth;
+ for (i = 0;i < outheight;i++)
+ {
+ inrow = (int *)indata + inwidth*(i*inheight/outheight);
+ frac = fracstep >> 1;
+ j = outwidth - 4;
+ while (j >= 0)
+ {
+ out[0] = inrow[frac >> 16];frac += fracstep;
+ out[1] = inrow[frac >> 16];frac += fracstep;
+ out[2] = inrow[frac >> 16];frac += fracstep;
+ out[3] = inrow[frac >> 16];frac += fracstep;
+ out += 4;
+ j -= 4;
+ }
+ if (j & 2)
+ {
+ out[0] = inrow[frac >> 16];frac += fracstep;
+ out[1] = inrow[frac >> 16];frac += fracstep;
+ out += 2;
+ }
+ if (j & 1)
+ {
+ out[0] = inrow[frac >> 16];frac += fracstep;
+ out += 1;
+ }
+ }
+}
+
+/*
+================
+Image_Resample
+================
+*/
+void Image_Resample32(const void *indata, int inwidth, int inheight, int indepth, void *outdata, int outwidth, int outheight, int outdepth, int quality)
+{
+ if (indepth != 1 || outdepth != 1)