]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - image.c
added newmap function to render modules (so explosions and other things are reset...
[xonotic/darkplaces.git] / image.c
diff --git a/image.c b/image.c
index a32d58a40599b498b156a612e48136450fd01aaf..a26b78fc600f309425b161c5542fe66e8d80e640 100644 (file)
--- a/image.c
+++ b/image.c
@@ -4,6 +4,58 @@
 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] = qgamma[in[0]];
+               out[1] = qgamma[in[1]];
+               out[2] = qgamma[in[2]];
+               out[3] =        in[3] ;
+               in += 4;
+               out += 4;
+       }
+}
+
+
 /*
 =================================================================
 
@@ -50,12 +102,17 @@ byte* LoadPCX (FILE *f, int matchwidth, int matchheight)
 
        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;
@@ -73,7 +130,7 @@ byte* LoadPCX (FILE *f, int matchwidth, int matchheight)
        fseek (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++)
        {
@@ -86,21 +143,32 @@ byte* LoadPCX (FILE *f, int matchwidth, int matchheight)
                        {
                                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;
+                                       }
+                               }
                        }
                        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++;
                        }
+
                }
        }
+       fclose(f);
        image_width = pcx->xmax+1;
        image_height = pcx->ymax+1;
        return image_rgba;
@@ -180,17 +248,17 @@ byte* LoadTGA (FILE *fin, int matchwidth, int matchheight)
 
        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
@@ -199,7 +267,7 @@ byte* LoadTGA (FILE *fin, int matchwidth, int matchheight)
                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:
                                                        
@@ -226,7 +294,7 @@ byte* LoadTGA (FILE *fin, int matchwidth, int matchheight)
                }
        }
        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; ) {
@@ -309,12 +377,63 @@ byte* LoadTGA (FILE *fin, int matchwidth, int matchheight)
        return image_rgba;
 }
 
+/*
+============
+LoadLMP
+============
+*/
+byte* LoadLMP (FILE *f, int matchwidth, int matchheight)
+{
+       byte    *image_rgba;
+       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);
+       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_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)
 {
        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
+       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);
        if (f)
@@ -331,29 +450,203 @@ byte* loadimagepixels (char* filename, qboolean complain, int matchwidth, int ma
        COM_FOpenFile (name, &f, 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);
+       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;
 }