int image_width;
int image_height;
+// note: pal must be 32bit color
+void Image_Copy8bitRGBA(byte *in, byte *out, int pixels, int *pal)
+{
+ int *iout = (void *)out;
+ while (pixels >= 8)
+ {
+ iout[0] = pal[in[0]];
+ iout[1] = pal[in[1]];
+ iout[2] = pal[in[2]];
+ iout[3] = pal[in[3]];
+ iout[4] = pal[in[4]];
+ iout[5] = pal[in[5]];
+ iout[6] = pal[in[6]];
+ iout[7] = pal[in[7]];
+ in += 8;
+ iout += 8;
+ pixels -= 8;
+ }
+ if (pixels & 4)
+ {
+ iout[0] = pal[in[0]];
+ iout[1] = pal[in[1]];
+ iout[2] = pal[in[2]];
+ iout[3] = pal[in[3]];
+ in += 4;
+ iout += 4;
+ }
+ if (pixels & 2)
+ {
+ iout[0] = pal[in[0]];
+ iout[1] = pal[in[1]];
+ in += 2;
+ iout += 2;
+ }
+ if (pixels & 1)
+ iout[0] = pal[in[0]];
+}
+
+void Image_CopyRGBAGamma(byte *in, byte *out, int pixels)
+{
+ while (pixels--)
+ {
+ out[0] = texgamma[in[0]];
+ out[1] = texgamma[in[1]];
+ out[2] = texgamma[in[2]];
+ out[3] = in[3] ;
+ in += 4;
+ out += 4;
+ }
+}
+
+
/*
=================================================================
LoadPCX
============
*/
-byte* LoadPCX (FILE *f, int matchwidth, int matchheight)
+byte* LoadPCX (QFile *f, int matchwidth, int matchheight)
{
pcx_t *pcx, pcxbuf;
byte palette[768];
//
// parse the PCX file
//
- fread (&pcxbuf, 1, sizeof(pcxbuf), f);
+ Qread (f, &pcxbuf, sizeof(pcxbuf));
pcx = &pcxbuf;
- 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;
return NULL;
// seek to palette
- fseek (f, -768, SEEK_END);
- fread (palette, 1, 768, f);
+ Qseek (f, -768, SEEK_END);
+ Qread (f, palette, 768);
- fseek (f, sizeof(pcxbuf) - 4, SEEK_SET);
+ Qseek (f, sizeof(pcxbuf) - 4, SEEK_SET);
count = (pcx->xmax+1) * (pcx->ymax+1);
- image_rgba = malloc( count * 4);
+ image_rgba = qmalloc( count * 4);
for (y=0 ; y<=pcx->ymax ; y++)
{
pix = image_rgba + 4*y*(pcx->xmax+1);
for (x=0 ; x<=pcx->xmax ; )
{
- dataByte = fgetc(f);
+ dataByte = Qgetc(f);
if((dataByte & 0xC0) == 0xC0)
{
runLength = dataByte & 0x3F;
- dataByte = fgetc(f);
+ dataByte = Qgetc(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;
+ }
+ }
}
else
- runLength = 1;
-
- while(runLength-- > 0)
{
+ x++;
pix[0] = palette[dataByte*3];
pix[1] = palette[dataByte*3+1];
pix[2] = palette[dataByte*3+2];
pix[3] = 255;
pix += 4;
- x++;
}
+
}
}
+ Qclose(f);
image_width = pcx->xmax+1;
image_height = pcx->ymax+1;
return image_rgba;
TargaHeader targa_header;
-int fgetLittleShort (FILE *f)
+int fgetLittleShort (QFile *f)
{
byte b1, b2;
- b1 = fgetc(f);
- b2 = fgetc(f);
+ b1 = Qgetc(f);
+ b2 = Qgetc(f);
return (short)(b1 + b2*256);
}
-int fgetLittleLong (FILE *f)
+int fgetLittleLong (QFile *f)
{
byte b1, b2, b3, b4;
- b1 = fgetc(f);
- b2 = fgetc(f);
- b3 = fgetc(f);
- b4 = fgetc(f);
+ b1 = Qgetc(f);
+ b2 = Qgetc(f);
+ b3 = Qgetc(f);
+ b4 = Qgetc(f);
return b1 + (b2<<8) + (b3<<16) + (b4<<24);
}
LoadTGA
=============
*/
-byte* LoadTGA (FILE *fin, int matchwidth, int matchheight)
+byte* LoadTGA (QFile *fin, 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.id_length = Qgetc(fin);
+ targa_header.colormap_type = Qgetc(fin);
+ targa_header.image_type = Qgetc(fin);
targa_header.colormap_index = fgetLittleShort(fin);
targa_header.colormap_length = fgetLittleShort(fin);
- targa_header.colormap_size = fgetc(fin);
+ targa_header.colormap_size = Qgetc(fin);
targa_header.x_origin = fgetLittleShort(fin);
targa_header.y_origin = fgetLittleShort(fin);
targa_header.width = fgetLittleShort(fin);
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 = Qgetc(fin);
+ targa_header.attributes = Qgetc(fin);
if (targa_header.image_type!=2
&& targa_header.image_type!=10)
- Sys_Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
+ 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))
- Sys_Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
+ 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);
if (targa_header.id_length != 0)
- fseek(fin, targa_header.id_length, SEEK_CUR); // skip TARGA image comment
+ Qseek(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--) {
pixbuf = image_rgba + row*columns*4;
for(column=0; column<columns; column++) {
- unsigned char red,green,blue,alphabyte;
+ 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);
+ blue = Qgetc(fin);
+ green = Qgetc(fin);
+ red = Qgetc(fin);
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
- blue = getc(fin);
- green = getc(fin);
- red = getc(fin);
- alphabyte = getc(fin);
+ blue = Qgetc(fin);
+ green = Qgetc(fin);
+ red = Qgetc(fin);
+ alphabyte = Qgetc(fin);
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
}
}
else if (targa_header.image_type==10) { // Runlength encoded RGB images
- unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
+ 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);
+ packetHeader=Qgetc(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);
+ blue = Qgetc(fin);
+ green = Qgetc(fin);
+ red = Qgetc(fin);
alphabyte = 255;
break;
case 32:
- blue = getc(fin);
- green = getc(fin);
- red = getc(fin);
- alphabyte = getc(fin);
+ blue = Qgetc(fin);
+ green = Qgetc(fin);
+ red = Qgetc(fin);
+ alphabyte = Qgetc(fin);
break;
}
for(j=0;j<packetSize;j++) {
switch (targa_header.pixel_size) {
case 24:
- blue = getc(fin);
- green = getc(fin);
- red = getc(fin);
+ blue = Qgetc(fin);
+ green = Qgetc(fin);
+ red = Qgetc(fin);
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
- blue = getc(fin);
- green = getc(fin);
- red = getc(fin);
- alphabyte = getc(fin);
+ blue = Qgetc(fin);
+ green = Qgetc(fin);
+ red = Qgetc(fin);
+ alphabyte = Qgetc(fin);
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
}
}
- fclose(fin);
+ Qclose(fin);
image_width = columns;
image_height = rows;
return image_rgba;
}
-byte* loadimagepixels (char* filename, qboolean complain, int matchwidth, int matchheight)
+/*
+============
+LoadLMP
+============
+*/
+byte* LoadLMP (QFile *f, int matchwidth, int matchheight)
{
- FILE *f;
- char basename[128], name[128];
byte *image_rgba;
- COM_StripExtension(filename, basename); // strip the extension to allow TGA skins on Q2 models despite the .pcx in the skin name
+ int width, height;
+
+ // parse the very complicated header *chuckle*
+ width = fgetLittleLong(f);
+ height = fgetLittleLong(f);
+ if ((unsigned) width > 4096 || (unsigned) height > 4096)
+ Host_Error("LoadLMP: invalid size\n");
+ if (matchwidth && width != matchwidth)
+ return NULL;
+ if (matchheight && height != matchheight)
+ return NULL;
+
+ image_rgba = qmalloc(width*height*4);
+ Qread(f, image_rgba + width*height*3, width*height);
+ Qclose(f);
+
+ Image_Copy8bitRGBA(image_rgba + width*height*3, image_rgba, width*height, d_8to24table);
+ image_width = width;
+ image_height = height;
+ 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)
+{
+ QFile *f;
+ char basename[256], name[256];
+ 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);
+ COM_FOpenFile (name, &f, true, true);
if (f)
return LoadTGA (f, matchwidth, matchheight);
sprintf (name, "textures/%s.pcx", basename);
- COM_FOpenFile (name, &f, true);
+ COM_FOpenFile (name, &f, true, true);
if (f)
return LoadPCX (f, matchwidth, matchheight);
sprintf (name, "%s.tga", basename);
- COM_FOpenFile (name, &f, true);
+ COM_FOpenFile (name, &f, true, true);
if (f)
return LoadTGA (f, matchwidth, matchheight);
sprintf (name, "%s.pcx", basename);
- COM_FOpenFile (name, &f, true);
+ COM_FOpenFile (name, &f, true, true);
if (f)
return LoadPCX (f, matchwidth, matchheight);
- if (image_rgba = W_GetTexture(basename, matchwidth, matchheight))
- return image_rgba;
+ sprintf (name, "%s.lmp", basename);
+ COM_FOpenFile (name, &f, true, true);
+ if (f)
+ return LoadLMP (f, matchwidth, matchheight);
if (complain)
Con_Printf ("Couldn't load %s.tga or .pcx\n", filename);
return NULL;
}
-int loadtextureimage (int texnum, char* filename, qboolean complain, int matchwidth, int matchheight)
+int image_makemask (byte *in, byte *out, int size)
+{
+ int i, count;
+ count = 0;
+ for (i = 0;i < size;i++)
+ {
+ out[0] = out[1] = out[2] = 255;
+ out[3] = in[3];
+ if (in[3] != 255)
+ count++;
+ in += 4;
+ out += 4;
+ }
+ return count;
+}
+
+byte* loadimagepixelsmask (char* filename, qboolean complain, int matchwidth, int matchheight)
+{
+ byte *in, *data;
+ in = data = loadimagepixels(filename, complain, matchwidth, matchheight);
+ if (!data)
+ return NULL;
+ if (image_makemask(data, data, image_width * image_height))
+ return data; // some transparency
+ else
+ {
+ qfree(data);
+ return NULL; // all opaque
+ }
+}
+
+rtexture_t *loadtextureimage (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache)
{
byte *data;
+ rtexture_t *rt;
if (!(data = loadimagepixels (filename, complain, matchwidth, matchheight)))
return 0;
- if (texnum >= 0) // specific texnum, not cached
+ 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;
+}
+
+rtexture_t *loadtextureimagemask (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache)
+{
+ byte *data;
+ rtexture_t *rt;
+ if (!(data = loadimagepixelsmask (filename, complain, matchwidth, matchheight)))
+ return 0;
+ 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;
+}
+
+rtexture_t *image_masktex;
+rtexture_t *loadtextureimagewithmask (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache)
+{
+ int count;
+ byte *data;
+ char *filename2;
+ rtexture_t *rt;
+ image_masktex = NULL;
+ if (!(data = loadimagepixels (filename, complain, matchwidth, matchheight)))
+ return 0;
+ 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 = qmalloc(strlen(filename) + 6);
+ sprintf(filename2, "%s_mask", filename);
+ image_masktex = R_LoadTexture (filename2, image_width, image_height, data, TEXF_ALPHA | TEXF_RGBA | (mipmap ? TEXF_MIPMAP : 0) | (mipmap ? TEXF_PRECACHE : 0));
+ qfree(filename2);
+ }
+ 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)
+{
+ int y;
+ 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 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 );
+
+ qfree(buffer);
+}
+
+void Image_WriteTGARGBA (char *filename, int width, int height, byte *data)
+{
+ int y;
+ byte *buffer, *in, *out, *end;
+
+ buffer = qmalloc(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 );
+
+ qfree(buffer);
+}
+
+qboolean Image_CheckAlpha(byte *data, int size, qboolean rgba)
+{
+ byte *end;
+ if (rgba)
{
- glBindTexture(GL_TEXTURE_2D, texnum);
- GL_Upload32 (data, image_width, image_height, true, true);
- free(data);
- return texnum;
+ // check alpha bytes
+ for (end = data + size * 4, data += 3;data < end;data += 4)
+ if (*data < 255)
+ return 1;
}
- else // any texnum, cached
+ else
{
- texnum = GL_LoadTexture (filename, image_width, image_height, data, true, true, 4);
- free(data);
- return texnum;
+ // color 255 is transparent
+ for (end = data + size;data < end;data++)
+ if (*data == 255)
+ return 1;
}
+ return 0;
}