]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - image.c
Fix setinfo.
[xonotic/darkplaces.git] / image.c
diff --git a/image.c b/image.c
index 58f7c053234b58f1de69363ef0618389a1887fe9..77b9435e66695d1cf3d1638bc667dfd323af4beb 100644 (file)
--- a/image.c
+++ b/image.c
@@ -4,10 +4,13 @@
 #include "jpeg.h"
 #include "image_png.h"
 #include "r_shadow.h"
+#include "wad.h"
 
 int            image_width;
 int            image_height;
 
+static unsigned char *Image_GetEmbeddedPicBGRA(const char *name);
+
 static void Image_CopyAlphaFromBlueBGRA(unsigned char *outpixels, const unsigned char *inpixels, int w, int h)
 {
        int i, n;
@@ -436,6 +439,8 @@ unsigned char *LoadTGA_BGRA (const unsigned char *f, int filesize, int *miplevel
                return NULL;
        }
 
+       memset(palettei, 0, sizeof(palettei));
+
        // advance to end of header
        fin = f + 18;
 
@@ -799,25 +804,111 @@ qboolean LoadWAL_GetMetadata(const unsigned char *f, int filesize, int *retwidth
        if (filesize < (int) sizeof(q2wal_t))
        {
                Con_Print("LoadWAL: invalid WAL file\n");
-               *retwidth = 16;
-               *retheight = 16;
-               *retflags = 0;
-               *retvalue = 0;
-               *retcontents = 0;
-               memset(retanimname32c, 0, 32);
+               if (retwidth)
+                       *retwidth = 16;
+               if (retheight)
+                       *retheight = 16;
+               if (retflags)
+                       *retflags = 0;
+               if (retvalue)
+                       *retvalue = 0;
+               if (retcontents)
+                       *retcontents = 0;
+               if (retanimname32c)
+                       memset(retanimname32c, 0, 32);
                return false;
        }
 
-       *retwidth = LittleLong(inwal->width);
-       *retheight = LittleLong(inwal->height);
-       *retflags = LittleLong(inwal->flags);
-       *retvalue = LittleLong(inwal->value);
-       *retcontents = LittleLong(inwal->contents);
-       memcpy(retanimname32c, inwal->animname, 32);
-       retanimname32c[31] = 0;
+       if (retwidth)
+               *retwidth = LittleLong(inwal->width);
+       if (retheight)
+               *retheight = LittleLong(inwal->height);
+       if (retflags)
+               *retflags = LittleLong(inwal->flags);
+       if (retvalue)
+               *retvalue = LittleLong(inwal->value);
+       if (retcontents)
+               *retcontents = LittleLong(inwal->contents);
+       if (retanimname32c)
+       {
+               memcpy(retanimname32c, inwal->animname, 32);
+               retanimname32c[31] = 0;
+       }
        return true;
 }
 
+// gfx/* wad lumps and gfx/*.lmp files are simply width and height and paletted pixels, with color 255 as transparent
+static unsigned char* LoadLMP_BGRA(const unsigned char *f, int filesize, int *miplevel)
+{
+       unsigned char *image_buffer;
+       int i;
+
+       if (filesize < 9)
+       {
+               Con_Print("Bad lmp file\n");
+               return NULL;
+       }
+
+       image_width = f[0] + f[1] * 0x100 + f[2] * 0x10000 + f[3] * 0x1000000;
+       image_height = f[4] + f[5] * 0x100 + f[6] * 0x10000 + f[7] * 0x1000000;
+
+       if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0 || image_width * image_height > filesize - 8)
+       {
+               Con_Print("Bad lmp file\n");
+               return NULL;
+       }
+
+       image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width*image_height * 4);
+       if (!image_buffer)
+       {
+               Con_Printf("LoadLMP: not enough memory for %i by %i image\n", image_width, image_height);
+               return NULL;
+       }
+
+       for (i = 0; i < image_width * image_height; i++)
+       {
+               const unsigned char *p = (const unsigned char *)palette_bgra_transparent + 4 * f[8 + i];
+               image_buffer[i * 4 + 0] = p[0];
+               image_buffer[i * 4 + 1] = p[1];
+               image_buffer[i * 4 + 2] = p[2];
+               image_buffer[i * 4 + 3] = p[3];
+       }
+
+       return image_buffer;
+}
+
+// gfx/conchars is a raw 128x128 image with 0 as transparent color rather than 255
+unsigned char *LoadConChars_BGRA(const unsigned char *f, int filesize, int *miplevel)
+{
+       unsigned char *image_buffer;
+       int i;
+
+       image_width = 128;
+       image_height = 128;
+       if (image_width * image_height > filesize)
+       {
+               Con_Print("Bad lmp file\n");
+               return NULL;
+       }
+
+       image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width*image_height * 4);
+       if (!image_buffer)
+       {
+               Con_Printf("LoadConChars: not enough memory for %i by %i image\n", image_width, image_height);
+               return NULL;
+       }
+
+       for (i = 0; i < image_width * image_height; i++)
+       {
+               const unsigned char *p = (const unsigned char *)palette_bgra_font + 4 * f[i];
+               image_buffer[i * 4 + 0] = p[0];
+               image_buffer[i * 4 + 1] = p[1];
+               image_buffer[i * 4 + 2] = p[2];
+               image_buffer[i * 4 + 3] = p[3];
+       }
+
+       return image_buffer;
+}
 
 void Image_StripImageExtension (const char *in, char *out, size_t size_out)
 {
@@ -934,6 +1025,7 @@ imageformat_t imageformats_gfx[] =
        {"%s.png", PNG_LoadImage_BGRA},
        {"%s.jpg", JPEG_LoadImage_BGRA},
        {"%s.pcx", LoadPCX_BGRA},
+       {"%s.lmp", LoadLMP_BGRA},
        {NULL, NULL}
 };
 
@@ -943,6 +1035,7 @@ imageformat_t imageformats_other[] =
        {"%s.png", PNG_LoadImage_BGRA},
        {"%s.jpg", JPEG_LoadImage_BGRA},
        {"%s.pcx", LoadPCX_BGRA},
+       {"%s.lmp", LoadLMP_BGRA},
        {NULL, NULL}
 };
 
@@ -952,7 +1045,7 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo
        fs_offset_t filesize;
        imageformat_t *firstformat, *format;
        unsigned char *f, *data = NULL, *data2 = NULL;
-       char basename[MAX_QPATH], name[MAX_QPATH], name2[MAX_QPATH], *c;
+       char basename[MAX_QPATH], name[MAX_QPATH], name2[MAX_QPATH], path[MAX_QPATH], afterpath[MAX_QPATH], *c;
        char vabuf[1024];
        //if (developer_memorydebug.integer)
        //      Mem_CheckSentinelsGlobal();
@@ -963,23 +1056,26 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo
        for (c = basename;*c;c++)
                if (*c == '*')
                        *c = '#';
+       path[0] = 0;
        name[0] = 0;
+       strlcpy(afterpath, basename, sizeof(afterpath));
        if (strchr(basename, '/'))
        {
                int i;
-               for (i = 0;i < (int)sizeof(name)-1 && basename[i] != '/';i++)
-                       name[i] = basename[i];
-               name[i] = 0;
+               for (i = 0;i < (int)sizeof(path)-1 && basename[i] != '/' && basename[i];i++)
+                       path[i] = basename[i];
+               path[i] = 0;
+               strlcpy(afterpath, basename + i + 1, sizeof(afterpath));
        }
        if (gamemode == GAME_TENEBRAE)
                firstformat = imageformats_tenebrae;
        else if (gamemode == GAME_DELUXEQUAKE)
                firstformat = imageformats_dq;
-       else if (!strcasecmp(name, "textures"))
+       else if (!strcasecmp(path, "textures"))
                firstformat = imageformats_textures;
-       else if (!strcasecmp(name, "gfx"))
+       else if (!strcasecmp(path, "gfx") || !strcasecmp(path, "locale")) // locale/ is used in GAME_BLOODOMNICIDE
                firstformat = imageformats_gfx;
-       else if (!strchr(basename, '/'))
+       else if (!path[0])
                firstformat = imageformats_nopath;
        else
                firstformat = imageformats_other;
@@ -1048,6 +1144,33 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo
                                Con_DPrintf("Error loading image %s (file loaded but decode failed)\n", name);
                }
        }
+       if (!strcasecmp(path, "gfx"))
+       {
+               unsigned char *lmpdata;
+               if ((lmpdata = W_GetLumpName(afterpath, &filesize)))
+               {
+                       if (developer_loading.integer)
+                               Con_Printf("loading gfx.wad lump \"%s\"\n", afterpath);
+
+                       int mymiplevel = miplevel ? *miplevel : 0;
+                       if (!strcmp(afterpath, "conchars"))
+                       {
+                               // conchars is a raw image and with color 0 as transparent instead of 255
+                               data = LoadConChars_BGRA(lmpdata, filesize, &mymiplevel);
+                       }
+                       else
+                               data = LoadLMP_BGRA(lmpdata, filesize, &mymiplevel);
+                       // no cleanup after looking up a wad lump - the whole gfx.wad is loaded at once
+                       if (data)
+                               return data;
+                       Con_DPrintf("Error loading image %s (file loaded but decode failed)\n", name);
+               }
+       }
+
+       // check if the image name exists as an embedded pic
+       if ((data = Image_GetEmbeddedPicBGRA(basename)))
+               return data;
+
        if (complain)
        {
                Con_Printf("Couldn't load %s using ", filename);
@@ -1063,9 +1186,58 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo
 
        //if (developer_memorydebug.integer)
        //      Mem_CheckSentinelsGlobal();
+
        return NULL;
 }
 
+qboolean Image_GetStockPicSize(const char *filename, int *returnwidth, int *returnheight)
+{
+       unsigned char *data;
+       fs_offset_t filesize;
+       char lmppath[MAX_QPATH];
+       if (!strcasecmp(filename, "gfx/conchars"))
+       {
+               *returnwidth = 128;
+               *returnheight = 128;
+               return true;
+       }
+
+       dpsnprintf(lmppath, sizeof(lmppath), "%s.lmp", filename);
+       data = FS_LoadFile(lmppath, tempmempool, true, &filesize);
+       if (data)
+       {
+               if (filesize > 8)
+               {
+                       int w = data[0] + data[1] * 0x100 + data[2] * 0x10000 + data[3] * 0x1000000;
+                       int h = data[4] + data[5] * 0x100 + data[6] * 0x10000 + data[7] * 0x1000000;
+                       if (w >= 1 && w <= 32768 && h >= 1 && h <= 32768)
+                       {
+                               *returnwidth = w;
+                               *returnheight = h;
+                               Mem_Free(data);
+                               return true;
+                       }
+               }
+               Mem_Free(data);
+       }
+       if (!strncasecmp(filename, "gfx/", 4))
+       {
+               data = W_GetLumpName(filename + 4, &filesize);
+               if (data && filesize > 8)
+               {
+                       int w = data[0] + data[1] * 0x100 + data[2] * 0x10000 + data[3] * 0x1000000;
+                       int h = data[4] + data[5] * 0x100 + data[6] * 0x10000 + data[7] * 0x1000000;
+                       if (w >= 1 && w <= 32768 && h >= 1 && h <= 32768)
+                       {
+                               *returnwidth = w;
+                               *returnheight = h;
+                               return true;
+                       }
+               }
+       }
+       return false;
+}
+
 extern cvar_t gl_picmip;
 rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qboolean complain, int flags, qboolean allowFixtrans, qboolean sRGB)
 {
@@ -1631,3 +1803,302 @@ void Image_HeightmapToNormalmap_BGRA(const unsigned char *inpixels, unsigned cha
                }
        }
 }
+
+static const unsigned char concharimage[] =
+{
+#include "lhfont.h"
+};
+
+static unsigned char *Image_GenerateConChars(void)
+{
+       int i;
+       unsigned char *data;
+       double random;
+
+       image_width = 256;
+       image_height = 256;
+
+       data = LoadTGA_BGRA(concharimage, sizeof(concharimage), NULL);
+       // Gold numbers
+       for (i = 0; i < 8192; i++)
+       {
+               random = lhrandom(0.0, 1.0);
+               data[i * 4 + 3] = data[i * 4 + 0];
+               data[i * 4 + 2] = 83 + (unsigned char)(random * 64);
+               data[i * 4 + 1] = 71 + (unsigned char)(random * 32);
+               data[i * 4 + 0] = 23 + (unsigned char)(random * 16);
+       }
+       // White chars
+       for (i = 8192; i < 32768; i++)
+       {
+               random = lhrandom(0.0, 1.0);
+               data[i * 4 + 3] = data[i * 4 + 0];
+               data[i * 4 + 2] = 95 + (unsigned char)(random * 64);
+               data[i * 4 + 1] = 95 + (unsigned char)(random * 64);
+               data[i * 4 + 0] = 95 + (unsigned char)(random * 64);
+       }
+       // Gold numbers
+       for (i = 32768; i < 40960; i++)
+       {
+               random = lhrandom(0.0, 1.0);
+               data[i * 4 + 3] = data[i * 4 + 0];
+               data[i * 4 + 2] = 83 + (unsigned char)(random * 64);
+               data[i * 4 + 1] = 71 + (unsigned char)(random * 32);
+               data[i * 4 + 0] = 23 + (unsigned char)(random * 16);
+       }
+       // Red chars
+       for (i = 40960; i < 65536; i++)
+       {
+               random = lhrandom(0.0, 1.0);
+               data[i * 4 + 3] = data[i * 4 + 0];
+               data[i * 4 + 2] = 96 + (unsigned char)(random * 64);
+               data[i * 4 + 1] = 43 + (unsigned char)(random * 32);
+               data[i * 4 + 0] = 27 + (unsigned char)(random * 32);
+       }
+
+#if 0
+       Image_WriteTGABGRA("gfx/generated_conchars.tga", 256, 256, data);
+#endif
+
+       return data;
+}
+
+static unsigned char *Image_GenerateDitherPattern(void)
+{
+       int x, y;
+       unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, 8 * 8 * 4);
+       image_width = 8;
+       image_height = 8;
+       for (y = 0; y < 8; y++)
+       {
+               for (x = 0; x < 8; x++)
+               {
+                       data[(y * 8 + x) * 4 + 0] = ((x^y) & 4) ? 255 : 0;
+                       data[(y * 8 + x) * 4 + 1] = ((x^y) & 4) ? 255 : 0;
+                       data[(y * 8 + x) * 4 + 2] = ((x^y) & 4) ? 255 : 0;
+                       data[(y * 8 + x) * 4 + 3] = 255;
+               }
+       }
+       return data;
+}
+
+// also used in R_SkinFrame code
+unsigned char *Image_GenerateNoTexture(void)
+{
+       int x, y;
+       unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, 16 * 16 * 4);
+       image_width = 16;
+       image_height = 16;
+       // this makes a light grey/dark grey checkerboard texture
+       for (y = 0; y < 16; y++)
+       {
+               for (x = 0; x < 16; x++)
+               {
+                       data[(y * 16 + x) * 4 + 0] =
+                       data[(y * 16 + x) * 4 + 1] =
+                       data[(y * 16 + x) * 4 + 2] = (y < 8) ^ (x < 8) ? 128 : 64;
+                       data[(y * 16 + x) * 4 + 3] = 255;
+               }
+       }
+       return data;
+}
+
+static unsigned char *Image_GenerateWhite(void)
+{
+       unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, 1 * 1 * 4);
+       image_width = 1;
+       image_height = 1;
+       data[0] = data[1] = data[2] = data[3] = 255;
+       return data;
+}
+
+typedef struct embeddedpic_s
+{
+const char *name;
+int width;
+int height;
+const char *pixels;
+}
+embeddedpic_t;
+
+static const embeddedpic_t embeddedpics[] =
+{
+       {
+               "gfx/prydoncursor001", 16, 16,
+               "477777774......."
+               "77.....6........"
+               "7.....6........."
+               "7....6.........."
+               "7.....6........."
+               "7..6...6........"
+               "7.6.6...6......."
+               "76...6...6......"
+               "4.....6.6......."
+               ".......6........"
+               "................"
+               "................"
+               "................"
+               "................"
+               "................"
+               "................"
+       },
+       {
+               "ui/mousepointer", 16, 16,
+               "477777774......."
+               "77.....6........"
+               "7.....6........."
+               "7....6.........."
+               "7.....6........."
+               "7..6...6........"
+               "7.6.6...6......."
+               "76...6...6......"
+               "4.....6.6......."
+               ".......6........"
+               "................"
+               "................"
+               "................"
+               "................"
+               "................"
+               "................"
+       },
+       {
+               "gfx/crosshair1", 16, 16,
+               "................"
+               "................"
+               "................"
+               "...33......33..."
+               "...355....553..."
+               "....577..775...."
+               ".....77..77....."
+               "................"
+               "................"
+               ".....77..77....."
+               "....577..775...."
+               "...355....553..."
+               "...33......33..."
+               "................"
+               "................"
+               "................"
+       },
+       {
+               "gfx/crosshair2", 16, 16,
+               "................"
+               "................"
+               "................"
+               "...3........3..."
+               "....5......5...."
+               ".....7....7....."
+               "......7..7......"
+               "................"
+               "................"
+               "......7..7......"
+               ".....7....7....."
+               "....5......5...."
+               "...3........3..."
+               "................"
+               "................"
+               "................"
+       },
+       {
+               "gfx/crosshair3", 16, 16,
+               "................"
+               ".......77......."
+               ".......77......."
+               "................"
+               "................"
+               ".......44......."
+               ".......44......."
+               ".77..44..44..77."
+               ".77..44..44..77."
+               ".......44......."
+               ".......44......."
+               "................"
+               "................"
+               ".......77......."
+               ".......77......."
+               "................"
+       },
+       {
+               "gfx/crosshair4", 16, 16,
+               "................"
+               "................"
+               "................"
+               "................"
+               "................"
+               "................"
+               "................"
+               "................"
+               "........7777777."
+               "........752....."
+               "........72......"
+               "........7......."
+               "........7......."
+               "........7......."
+               "........7......."
+               "................"
+       },
+       {
+               "gfx/crosshair5", 8, 8,
+               "........"
+               "........"
+               "....7..."
+               "........"
+               "..7.7.7."
+               "........"
+               "....7..."
+               "........"
+       },
+       {
+               "gfx/crosshair6", 2, 2,
+               "77"
+               "77"
+       },
+       {
+               "gfx/crosshair7", 16, 16,
+               "................"
+               ".3............3."
+               "..5...2332...5.."
+               "...7.3....3.7..."
+               "....7......7...."
+               "...3.7....7.3..."
+               "..2...7..7...2.."
+               "..3..........3.."
+               "..3..........3.."
+               "..2...7..7...2.."
+               "...3.7....7.3..."
+               "....7......7...."
+               "...7.3....3.7..."
+               "..5...2332...5.."
+               ".3............3."
+               "................"
+       },
+       { NULL, 0, 0, NULL }
+};
+
+unsigned char *Image_GetEmbeddedPicBGRA(const char *name)
+{
+       const embeddedpic_t *p;
+       for (p = embeddedpics; p->name; p++)
+       {
+               if (!strcmp(name, p->name))
+               {
+                       int i;
+                       unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, p->width * p->height * 4);
+                       image_width = p->width;
+                       image_height = p->height;
+                       for (i = 0; i < p->width * p->height; i++)
+                       {
+                               const unsigned char *c = (const unsigned char *)palette_bgra_embeddedpic + 4 * p->pixels[i];
+                               Vector4Copy(c, data + 4 * i);
+                       }
+                       return data;
+               }
+       }
+       if (!strcmp(name, "white"))
+               return Image_GenerateWhite();
+       if (!strcmp(name, "gfx/conchars"))
+               return Image_GenerateConChars();
+       if (!strcmp(name, "gfx/colorcontrol/ditherpattern"))
+               return Image_GenerateDitherPattern();
+       return NULL;
+}