]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake2/qdata_heretic2/images.c
set eol-style
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / images.c
index bdc8ba5009cb24274c899f9b3edb99b5bb7c653b..c2dc29fbad2b42173eee11051336a8183c5d7f6e 100644 (file)
-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*/\r
-\r
-#include "qdata.h"\r
-\r
-#ifdef _WIN32\r
- #include <windows.h>\r
-#endif\r
-\r
-#include <GL/gl.h>\r
-\r
-#if 1\r
-       extern char             *g_outputDir;\r
-#endif // _QDATA\r
-\r
-char           mip_prefix[1024];               // directory to dump the textures in\r
-\r
-qboolean       colormap_issued;\r
-byte           colormap_palette[768];\r
-\r
-unsigned total_x = 0;\r
-unsigned total_y = 0;\r
-unsigned total_textures = 0;\r
-\r
-#define MAX_IMAGE_SIZE 512\r
-\r
-#if    0\r
-/*\r
-==============\r
-RemapZero\r
-\r
-Replaces all 0 bytes in an image with the closest palette entry.\r
-This is because NT won't let us change index 0, so any palette\r
-animation leaves those pixels untouched.\r
-==============\r
-*/\r
-void RemapZero (byte *pixels, byte *palette, int width, int height)\r
-{\r
-       int             i, c;\r
-       int             alt_zero;\r
-       int             value, best;\r
-\r
-       alt_zero = 0;\r
-       best = 9999999;\r
-       for (i=1 ; i<255 ; i++)\r
-       {\r
-               value = palette[i*3+0]+palette[i*3+1]+palette[i*3+2];\r
-               if (value < best)\r
-               {\r
-                       best = value;\r
-                       alt_zero = i;\r
-               }\r
-       }\r
-\r
-       c = width*height;\r
-       for (i=0 ; i<c ; i++)\r
-               if (pixels[i] == 0)\r
-                       pixels[i] = alt_zero;\r
-}\r
-\r
-#endif\r
-\r
-\r
-// ********************************************************************\r
-// **  Mip Map Pre-Processing Routines\r
-// ********************************************************************\r
-\r
-#define intensity_value 1\r
-\r
-static unsigned image_pal[256];\r
-\r
-#define MAX_LAST 25\r
-\r
-long palette_r[256], palette_g[256], palette_b[256];\r
-long last_r[MAX_LAST],last_g[MAX_LAST],last_b[MAX_LAST], last_i[MAX_LAST], last_place;\r
-\r
-long cached;\r
-\r
-void PrepareConvert(unsigned *palette)\r
-{\r
-       int i;\r
-\r
-       for(i=0;i<256;i++)\r
-       {\r
-               palette_r[i] = (palette[i] & 0x00ff0000) >> 16;\r
-               palette_g[i] = (palette[i] & 0x0000ff00) >> 8;\r
-               palette_b[i] = (palette[i] & 0x000000ff);\r
-       }\r
-\r
-       for(i=0;i<MAX_LAST;i++)\r
-               last_r[i] = -1;\r
-\r
-       last_place = -1;\r
-}\r
-\r
-int ConvertTrueColorToPal(unsigned r, unsigned g, unsigned b)\r
-{\r
-       int i;\r
-       long min_dist;\r
-       int min_index;\r
-       long dist;\r
-       long dr, dg, db, biggest_delta;\r
-\r
-       for(i=0;i<MAX_LAST;i++)\r
-               if (r == last_r[i] && g == last_g[i] && b == last_b[i])\r
-               {\r
-                       cached++;\r
-                       return last_i[i];\r
-               }\r
-\r
-       min_dist = 256 * 256 + 256 * 256 + 256 * 256;\r
-       biggest_delta = 256*256;\r
-       min_index = 0;\r
-\r
-       for (i=0;i<256;i++)\r
-       {\r
-               dr = abs(palette_r[i] - r);\r
-               if (dr > biggest_delta)\r
-                       continue;\r
-               dg = abs(palette_g[i] - g);\r
-               if (dg > biggest_delta)\r
-                       continue;\r
-               db = abs(palette_b[i] - b);\r
-               if (db > biggest_delta)\r
-                       continue;\r
-\r
-               dist = dr * dr + dg * dg + db * db;\r
-               if (dist < min_dist)\r
-               {\r
-                       min_dist = dist;\r
-                       min_index = i;\r
-                       if (min_dist == 0) break;\r
-\r
-                       dist = dr;\r
-                       if (dg > dist) dist = dg;\r
-                       if (db > dist) dist = db;\r
-                       if (dist < biggest_delta)\r
-                               biggest_delta = dist;\r
-               }\r
-       }\r
-\r
-       last_place++;\r
-       if (last_place >= MAX_LAST)\r
-               last_place = 0;\r
-\r
-       last_r[last_place] = r;\r
-       last_g[last_place] = g;\r
-       last_b[last_place] = b;\r
-       last_i[last_place] = min_index;\r
-\r
-       return min_index;\r
-}\r
-\r
-\r
-void GL_ResampleTexture8P (byte *in, int inwidth, int inheight, byte *out,  \r
-                                                  int outwidth, int outheight, palette_t *palette)\r
-{\r
-       int             i, j;\r
-       byte    *inrow, *inrow2;\r
-       unsigned        frac, fracstep;\r
-       unsigned        p1[1024], p2[1024], *p1p, *p2p;\r
-       palette_t       *c1,*c2,*c3,*c4;\r
-       unsigned        r,g,b;\r
-       \r
-       fracstep = inwidth*0x10000/outwidth;\r
-\r
-       frac = fracstep>>2;\r
-       for (i=0 ; i<outwidth ; i++)\r
-       {\r
-               p1[i] = frac>>16;\r
-               frac += fracstep;\r
-       }\r
-       frac = 3*(fracstep>>2);\r
-       for (i=0 ; i<outwidth ; i++)\r
-       {\r
-               p2[i] = frac>>16;\r
-               frac += fracstep;\r
-       }\r
-\r
-       cached = 0;\r
-       \r
-       for (i=0 ; i<outheight ; i++)//, out += outwidth)\r
-       {\r
-               inrow = in + inwidth*(int)((i+0.25)*inheight/outheight);\r
-               inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight);\r
-\r
-               p1p = p1;\r
-               p2p = p2;\r
-               for (j=0 ; j<outwidth ; j++)\r
-               {\r
-                       c1 = &palette[*((byte *)inrow + (*p1p))];\r
-                       c2 = &palette[*((byte *)inrow + (*p2p))];\r
-                       c3 = &palette[*((byte *)inrow2 + (*p1p++))];\r
-                       c4 = &palette[*((byte *)inrow2 + (*p2p++))];\r
-\r
-                       r = ((unsigned)c1->r + (unsigned)c2->r + (unsigned)c3->r + (unsigned)c4->r)>>2;\r
-                       g = ((unsigned)c1->g + (unsigned)c2->g + (unsigned)c3->g + (unsigned)c4->g)>>2;\r
-                       b = ((unsigned)c1->b + (unsigned)c2->b + (unsigned)c3->b + (unsigned)c4->b)>>2;\r
-\r
-                       *out++ = ConvertTrueColorToPal(r,g,b);\r
-               }\r
-       }\r
-}\r
-\r
-void GL_MipMap8P(byte *out, byte *in, int width, int height, palette_t *palette)\r
-{\r
-       int                     i, j;\r
-       palette_t       *c1,*c2,*c3,*c4;\r
-       unsigned        r,g,b;\r
-\r
-       cached = 0;\r
-       memset(out, 0, 256 * 256);\r
-       width <<= 1;\r
-       height <<= 1;\r
-\r
-       for (i = 0; i < height; i += 2, in += width)\r
-       {\r
-               for (j = 0; j < width; j += 2)\r
-               {\r
-                       c1 = &palette[in[0]];\r
-                       c3 = &palette[in[width]];\r
-                       in++;\r
-                       c2 = &palette[in[0]];\r
-                       c4 = &palette[in[width]];\r
-                       in++;\r
-\r
-                       r = ((unsigned)c1->r + (unsigned)c2->r + (unsigned)c3->r + (unsigned)c4->r) >> 2;\r
-                       g = ((unsigned)c1->g + (unsigned)c2->g + (unsigned)c3->g + (unsigned)c4->g) >> 2;\r
-                       b = ((unsigned)c1->b + (unsigned)c2->b + (unsigned)c3->b + (unsigned)c4->b) >> 2;\r
-\r
-                       *out++ = ConvertTrueColorToPal(r, g, b);\r
-               }\r
-       }\r
-}\r
-\r
-\r
-miptex_t *CreateMip(byte *data, unsigned width, unsigned height, byte *palette, int *FinalSize, qboolean mip)\r
-{\r
-       int                     scaled_width, scaled_height;\r
-       int                     i,j,r,g,b;\r
-       byte            intensitytable[256];\r
-       byte            scaled[256*256];\r
-       byte            out[256*256];\r
-       int                     miplevel;\r
-       miptex_t        *mp;\r
-       byte            *pos;\r
-       int                     size;\r
-\r
-       for (i=0 ; i<256 ; i++)\r
-       {\r
-               j = i * intensity_value;\r
-               if (j > 255)\r
-                       j = 255;\r
-               intensitytable[i] = j;\r
-       }\r
-\r
-       for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)\r
-               ;\r
-       if (1 && scaled_width > width && 1)\r
-               scaled_width >>= 1;\r
-       for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)\r
-               ;\r
-       if (1 && scaled_height > height && 1)\r
-               scaled_height >>= 1;\r
-\r
-       // don't ever bother with >256 textures\r
-       if (scaled_width > 256)\r
-               scaled_width = 256;\r
-       if (scaled_height > 256)\r
-               scaled_height = 256;\r
-\r
-       if (scaled_width < 1)\r
-               scaled_width = 1;\r
-       if (scaled_height < 1)\r
-               scaled_height = 1;\r
-\r
-       size = sizeof(*mp) + (scaled_width*scaled_height*3);\r
-       mp = (miptex_t *)SafeMalloc(size, "CreateMip");\r
-       memset(mp,0,size);\r
-\r
-       mp->version = MIP_VERSION;\r
-\r
-       for(i=j=0;i<256;i++,j+=3)\r
-       {\r
-               mp->palette[i].r = r = intensitytable[palette[j]];\r
-               mp->palette[i].g = g = intensitytable[palette[j+1]];\r
-               mp->palette[i].b = b = intensitytable[palette[j+2]];\r
-               image_pal[i] = 0xff000000 | (r<<16) | (g<<8) | (b);\r
-       }\r
-\r
-       PrepareConvert(image_pal);\r
-\r
-       if (scaled_width == width && scaled_height == height)\r
-       {\r
-               memcpy (scaled, data, width*height);\r
-       }\r
-       else\r
-               GL_ResampleTexture8P (data, width, height, scaled, scaled_width, scaled_height, mp->palette);\r
-\r
-       pos = (byte *)(mp + 1);\r
-       miplevel = 0;\r
-\r
-       while ((scaled_width >= 1 || scaled_height >= 1) && (miplevel <= MIPLEVELS-1) && (!miplevel || mip))\r
-       {\r
-               if (scaled_width < 1)\r
-                       scaled_width = 1;\r
-               if (scaled_height < 1)\r
-                       scaled_height = 1;\r
-\r
-               if(miplevel > 0)\r
-                       GL_MipMap8P(out, (byte *)scaled, scaled_width, scaled_height, mp->palette);\r
-               else\r
-                       memcpy(out, scaled, 256 * 256);\r
-\r
-               mp->width[miplevel] = scaled_width;\r
-               mp->height[miplevel] = scaled_height;\r
-               mp->offsets[miplevel] = pos - ((byte *)(mp));\r
-               memcpy(pos, out, scaled_width * scaled_height);\r
-               memcpy(scaled, out, 256 * 256);\r
-               pos += scaled_width * scaled_height;\r
-\r
-               scaled_width >>= 1;\r
-               scaled_height >>= 1;\r
-\r
-               miplevel++;\r
-       }\r
-\r
-       *FinalSize = pos - ((byte *)(mp));\r
-\r
-       return mp;\r
-}\r
-\r
-\r
-void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out,  int outwidth, int outheight)\r
-{\r
-       int             i, j;\r
-       unsigned        *inrow, *inrow2;\r
-       unsigned        frac, fracstep;\r
-       unsigned        p1[1024], p2[1024];\r
-       byte            *pix1, *pix2, *pix3, *pix4;\r
-\r
-       fracstep = inwidth*0x10000/outwidth;\r
-\r
-       frac = fracstep>>2;\r
-       for (i=0 ; i<outwidth ; i++)\r
-       {\r
-               p1[i] = 4*(frac>>16);\r
-               frac += fracstep;\r
-       }\r
-       frac = 3*(fracstep>>2);\r
-       for (i=0 ; i<outwidth ; i++)\r
-       {\r
-               p2[i] = 4*(frac>>16);\r
-               frac += fracstep;\r
-       }\r
-\r
-       for (i=0 ; i<outheight ; i++, out += outwidth)\r
-       {\r
-               inrow = in + inwidth*(int)((i+0.25)*inheight/outheight);\r
-               inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight);\r
-               frac = fracstep >> 1;\r
-               for (j=0 ; j<outwidth ; j++)\r
-               {\r
-                       pix1 = (byte *)inrow + p1[j];\r
-                       pix2 = (byte *)inrow + p2[j];\r
-                       pix3 = (byte *)inrow2 + p1[j];\r
-                       pix4 = (byte *)inrow2 + p2[j];\r
-                       ((byte *)(out+j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>2;\r
-                       ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2;\r
-                       ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2;\r
-                       ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2;\r
-               }\r
-       }\r
-}\r
-\r
-void GL_MipMap (byte *out, byte *in, int width, int height)\r
-{\r
-       int             i, j;\r
-\r
-       width <<=3;\r
-       height <<= 1;\r
-       for (i=0 ; i<height ; i++, in+=width)\r
-       {\r
-               for (j=0 ; j<width ; j+=8, out+=4, in+=8)\r
-               {\r
-                       out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>2;\r
-                       out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2;\r
-                       out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2;\r
-                       out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2;\r
-               }\r
-       }\r
-}\r
-\r
-miptex32_t *CreateMip32(unsigned *data, unsigned width, unsigned height, int *FinalSize, qboolean mip)\r
-{\r
-       int                             scaled_width, scaled_height;\r
-       unsigned                scaled[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE];\r
-       unsigned                out[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE];\r
-       int                             miplevel;\r
-       miptex32_t              *mp;\r
-       byte                    *pos;\r
-       int                             size;\r
-       paletteRGBA_t   *test;\r
-\r
-       for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)\r
-               ;\r
-       if (1 && scaled_width > width && 1)\r
-               scaled_width >>= 1;\r
-       for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)\r
-               ;\r
-       if (1 && scaled_height > height && 1)\r
-               scaled_height >>= 1;\r
-\r
-       // don't ever bother with >256 textures\r
-       if (scaled_width > MAX_IMAGE_SIZE)\r
-               scaled_width = MAX_IMAGE_SIZE;\r
-       if (scaled_height > MAX_IMAGE_SIZE)\r
-               scaled_height = MAX_IMAGE_SIZE;\r
-\r
-       if (scaled_width < 1)\r
-               scaled_width = 1;\r
-       if (scaled_height < 1)\r
-               scaled_height = 1;\r
-\r
-       size = sizeof(*mp) + (scaled_width*scaled_height*3*4);\r
-       mp = (miptex32_t *)SafeMalloc(size, "CreateMip");\r
-       memset(mp,0,size);\r
-\r
-       mp->version = MIP32_VERSION;\r
-\r
-       size = width*height;\r
-       test = (paletteRGBA_t *)data;\r
-       while(size)\r
-       {\r
-               if (test->a != 255)\r
-               {\r
-                       mp->flags |= LittleLong(SURF_ALPHA_TEXTURE);\r
-                       break;\r
-               }\r
-\r
-               size--;\r
-               test++;\r
-       }\r
-\r
-       if (scaled_width == width && scaled_height == height)\r
-       {\r
-               memcpy (scaled, data, width*height*4);\r
-       }\r
-       else\r
-               GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);\r
-\r
-       pos = (byte *)(mp + 1);\r
-       miplevel = 0;\r
-\r
-       while ((scaled_width >= 1 || scaled_height >= 1) && (miplevel <= MIPLEVELS-1) && (!miplevel || mip))\r
-       {\r
-               if (scaled_width < 1)\r
-                       scaled_width = 1;\r
-               if (scaled_height < 1)\r
-                       scaled_height = 1;\r
-\r
-               if (miplevel > 0)\r
-               {\r
-                       GL_MipMap((byte *)out, (byte *)scaled, scaled_width, scaled_height);\r
-               }\r
-               else\r
-               {\r
-                       memcpy(out, scaled, MAX_IMAGE_SIZE * MAX_IMAGE_SIZE * 4);\r
-               }\r
-\r
-               mp->width[miplevel] = scaled_width;\r
-               mp->height[miplevel] = scaled_height;\r
-               mp->offsets[miplevel] = pos - ((byte *)(mp));\r
-               memcpy(pos, out, scaled_width * scaled_height * 4);\r
-               memcpy(scaled, out, MAX_IMAGE_SIZE * MAX_IMAGE_SIZE * 4);\r
-               pos += scaled_width * scaled_height * 4;\r
-\r
-               scaled_width >>= 1;\r
-               scaled_height >>= 1;\r
-\r
-               miplevel++;\r
-       }\r
-\r
-       *FinalSize = pos - ((byte *)(mp));\r
-\r
-       return mp;\r
-}\r
-\r
-/*\r
-==============\r
-Cmd_Grab\r
-\r
-$grab filename x y width height\r
-==============\r
-*/\r
-void Cmd_Grab (void)\r
-{\r
-       int             xl,yl,w,h,y;\r
-       byte                    *cropped;\r
-       char                    savename[1024];\r
-       char                    dest[1024];\r
-\r
-       GetScriptToken (false);\r
-\r
-       if (token[0] == '/' || token[0] == '\\')\r
-               sprintf (savename, "%s%s.pcx", gamedir, token+1);\r
-       else\r
-               sprintf (savename, "%spics/%s.pcx", gamedir, token);\r
-\r
-       if (g_release)\r
-       {\r
-               if (token[0] == '/' || token[0] == '\\')\r
-                       sprintf (dest, "%s.pcx", token+1);\r
-               else\r
-                       sprintf (dest, "pics/%s.pcx", token);\r
-\r
-               ReleaseFile (dest);\r
-               return;\r
-       }\r
-\r
-       GetScriptToken (false);\r
-       xl = atoi (token);\r
-       GetScriptToken (false);\r
-       yl = atoi (token);\r
-       GetScriptToken (false);\r
-       w = atoi (token);\r
-       GetScriptToken (false);\r
-       h = atoi (token);\r
-\r
-       if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight)\r
-               Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h);\r
-\r
-       // crop it to the proper size\r
-       cropped = (byte *) SafeMalloc (w*h, "Cmd_Grab");\r
-       for (y=0 ; y<h ; y++)\r
-       {\r
-               memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);\r
-       }\r
-\r
-       // save off the new image\r
-       printf ("saving %s\n", savename);\r
-       CreatePath (savename);\r
-       WritePCXfile (savename, cropped, w,     h, lbmpalette);\r
-\r
-       free (cropped);\r
-}\r
-\r
-/*\r
-==============\r
-Cmd_Raw\r
-\r
-$grab filename x y width height\r
-==============\r
-*/\r
-void Cmd_Raw (void)\r
-{\r
-       int             xl,yl,w,h,y;\r
-       byte                    *cropped;\r
-       char                    savename[1024];\r
-       char                    dest[1024];\r
-\r
-       GetScriptToken (false);\r
-\r
-       sprintf (savename, "%s%s.lmp", gamedir, token);\r
-\r
-       if (g_release)\r
-       {\r
-               sprintf (dest, "%s.lmp", token);\r
-               ReleaseFile (dest);\r
-               return;\r
-       }\r
-\r
-       GetScriptToken (false);\r
-       xl = atoi (token);\r
-       GetScriptToken (false);\r
-       yl = atoi (token);\r
-       GetScriptToken (false);\r
-       w = atoi (token);\r
-       GetScriptToken (false);\r
-       h = atoi (token);\r
-\r
-       if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight)\r
-               Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h);\r
-\r
-       // crop it to the proper size\r
-       cropped = (byte *) SafeMalloc (w*h, "Cmd_Raw");\r
-       for (y=0 ; y<h ; y++)\r
-       {\r
-               memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);\r
-       }\r
-\r
-       // save off the new image\r
-       printf ("saving %s\n", savename);\r
-       CreatePath (savename);\r
-\r
-       SaveFile (savename, cropped, w*h);\r
-\r
-       free (cropped);\r
-}\r
-\r
-/*\r
-=============================================================================\r
-\r
-COLORMAP GRABBING\r
-\r
-=============================================================================\r
-*/\r
-\r
-/*\r
-===============\r
-BestColor\r
-===============\r
-*/\r
-byte BestColor (int r, int g, int b, int start, int stop)\r
-{\r
-       int     i;\r
-       int     dr, dg, db;\r
-       int     bestdistortion, distortion;\r
-       int     bestcolor;\r
-       byte    *pal;\r
-\r
-//\r
-// let any color go to 0 as a last resort\r
-//\r
-       bestdistortion = 256*256*4;\r
-       bestcolor = 0;\r
-\r
-       pal = colormap_palette + start*3;\r
-       for (i=start ; i<= stop ; i++)\r
-       {\r
-               dr = r - (int)pal[0];\r
-               dg = g - (int)pal[1];\r
-               db = b - (int)pal[2];\r
-               pal += 3;\r
-               distortion = dr*dr + dg*dg + db*db;\r
-               if (distortion < bestdistortion)\r
-               {\r
-                       if (!distortion)\r
-                               return i;               // perfect match\r
-\r
-                       bestdistortion = distortion;\r
-                       bestcolor = i;\r
-               }\r
-       }\r
-\r
-       return bestcolor;\r
-}\r
-\r
-\r
-/*\r
-==============\r
-Cmd_Colormap\r
-\r
-$colormap filename\r
-\r
-  the brightes colormap is first in the table (FIXME: reverse this now?)\r
-\r
-  64 rows of 256 : lightmaps\r
-  256 rows of 256 : translucency table\r
-==============\r
-*/\r
-void Cmd_Colormap (void)\r
-{\r
-       int             levels, brights;\r
-       int             l, c;\r
-       float   frac, red, green, blue;\r
-       float   range;\r
-       byte    *cropped, *lump_p;\r
-       char    savename[1024];\r
-       char    dest[1024];\r
-\r
-       colormap_issued = true;\r
-       if (!g_release)\r
-               memcpy (colormap_palette, lbmpalette, 768);\r
-\r
-       if (!ScriptTokenAvailable ())\r
-       {       // just setting colormap_issued\r
-               return;\r
-       }\r
-\r
-       GetScriptToken (false);\r
-       sprintf (savename, "%spics/%s.pcx", gamedir, token);\r
-\r
-       if (g_release)\r
-       {\r
-               sprintf (dest, "pics/%s.pcx", token);\r
-               ReleaseFile (dest);\r
-               return;\r
-       }\r
-\r
-       range = 2;\r
-       levels = 64;\r
-       brights = 1;    // ignore 255 (transparent)\r
-\r
-       cropped = (byte *) SafeMalloc((levels+256)*256, "Cmd_ColorMap");\r
-       lump_p = cropped;\r
-\r
-// shaded levels\r
-       for (l=0;l<levels;l++)\r
-       {\r
-               frac = range - range*(float)l/(levels-1);\r
-               for (c=0 ; c<256-brights ; c++)\r
-               {\r
-                       red = lbmpalette[c*3];\r
-                       green = lbmpalette[c*3+1];\r
-                       blue = lbmpalette[c*3+2];\r
-\r
-                       red = (int)(red*frac+0.5);\r
-                       green = (int)(green*frac+0.5);\r
-                       blue = (int)(blue*frac+0.5);\r
-                       \r
-//\r
-// note: 254 instead of 255 because 255 is the transparent color, and we\r
-// don't want anything remapping to that\r
-// don't use color 0, because NT can't remap that (or 255)\r
-//\r
-                       *lump_p++ = BestColor(red,green,blue, 1, 254);\r
-               }\r
-\r
-               // fullbrights allways stay the same\r
-               for ( ; c<256 ; c++)\r
-                       *lump_p++ = c;\r
-       }\r
-       \r
-// 66% transparancy table\r
-       for (l=0;l<255;l++)\r
-       {\r
-               for (c=0 ; c<255 ; c++)\r
-               {\r
-                       red = lbmpalette[c*3]*0.33 + lbmpalette[l*3]*0.66;\r
-                       green = lbmpalette[c*3+1]*0.33 + lbmpalette[l*3+1]*0.66;\r
-                       blue = lbmpalette[c*3+2]*0.33 + lbmpalette[l*3+2]*0.66;\r
-\r
-                       *lump_p++ = BestColor(red,green,blue, 1, 254);\r
-               }\r
-               *lump_p++ = 255;\r
-       }\r
-       for (c=0 ; c<256 ; c++)\r
-               *lump_p++ = 255;\r
-       \r
-       // save off the new image\r
-       printf ("saving %s\n", savename);\r
-       CreatePath (savename);\r
-       WritePCXfile (savename, cropped, 256, levels+256, lbmpalette);\r
-\r
-       free (cropped);\r
-}\r
-\r
-/*\r
-=============================================================================\r
-\r
-MIPTEX GRABBING\r
-\r
-=============================================================================\r
-*/\r
-\r
-byte   pixdata[256];\r
-\r
-int            d_red, d_green, d_blue;\r
-\r
-byte   palmap[32][32][32];\r
-qboolean       palmap_built;\r
-\r
-/*\r
-=============\r
-FindColor\r
-=============\r
-*/\r
-int FindColor (int r, int g, int b)\r
-{\r
-       int             bestcolor;\r
-\r
-       if (r > 255)\r
-               r = 255;\r
-       if (r < 0)\r
-               r = 0;\r
-       if (g > 255)\r
-               g = 255;\r
-       if (g < 0)\r
-               g = 0;\r
-       if (b > 255)\r
-               b = 255;\r
-       if (b < 0)\r
-               b = 0;\r
-#ifndef TABLECOLORS\r
-       bestcolor = BestColor (r, g, b, 0, 254);\r
-#else\r
-       bestcolor = palmap[r>>3][g>>3][b>>3];\r
-#endif\r
-\r
-       return bestcolor;\r
-}\r
-\r
-\r
-void BuildPalmap (void)\r
-{\r
-#ifdef TABLECOLORS\r
-       int             r, g, b;\r
-       int             bestcolor;\r
-\r
-       if (palmap_built)\r
-               return;\r
-       palmap_built = true;\r
-\r
-       for (r=4 ; r<256 ; r+=8)\r
-       {\r
-               for (g=4 ; g<256 ; g+=8)\r
-               {\r
-                       for (b=4 ; b<256 ; b+=8)\r
-                       {\r
-                               bestcolor = BestColor (r, g, b, 1, 254);\r
-                               palmap[r>>3][g>>3][b>>3] = bestcolor;\r
-                       }\r
-               }\r
-       }\r
-#endif\r
-\r
-       if (!colormap_issued)\r
-               Error ("You must issue a $colormap command first");\r
-\r
-}\r
-\r
-/*\r
-=============\r
-AveragePixels\r
-=============\r
-*/\r
-byte AveragePixels (int count)\r
-{\r
-       int             r,g,b;\r
-       int             i;\r
-       int             vis;\r
-       int             pix;\r
-       int             bestcolor;\r
-       byte    *pal;\r
-       int             fullbright;\r
-       \r
-       vis = 0;\r
-       r = g = b = 0;\r
-       fullbright = 0;\r
-       for (i=0 ; i<count ; i++)\r
-       {\r
-               pix = pixdata[i];\r
-               \r
-               r += lbmpalette[pix*3];\r
-               g += lbmpalette[pix*3+1];\r
-               b += lbmpalette[pix*3+2];\r
-               vis++;\r
-       }\r
-               \r
-       r /= vis;\r
-       g /= vis;\r
-       b /= vis;\r
-\r
-       // error diffusion\r
-       r += d_red;\r
-       g += d_green;\r
-       b += d_blue;\r
-       \r
-//\r
-// find the best color\r
-//\r
-       bestcolor = FindColor (r, g, b);\r
-\r
-       // error diffusion\r
-       pal = colormap_palette + bestcolor*3;\r
-       d_red = r - (int)pal[0];\r
-       d_green = g - (int)pal[1];\r
-       d_blue = b - (int)pal[2];\r
-\r
-       return bestcolor;\r
-}\r
-\r
-\r
-typedef enum\r
-{\r
-       pt_contents,\r
-       pt_flags,\r
-       pt_animvalue,\r
-       pt_altnamevalue,\r
-       pt_damagenamevalue,\r
-       pt_flagvalue,\r
-       pt_materialvalue,\r
-       pt_scale,\r
-       pt_mip,\r
-       pt_detail,\r
-       pt_gl,\r
-       pt_nomip,\r
-       pt_detailer,\r
-} parmtype_t;\r
-\r
-typedef struct\r
-{\r
-       char    *name;\r
-       int             flags;\r
-       parmtype_t      type;\r
-} mipparm_t;\r
-\r
-mipparm_t      mipparms[] =\r
-{\r
-       // utility content attributes\r
-       {"pushpull",CONTENTS_PUSHPULL, pt_contents},\r
-       {"water",       CONTENTS_WATER, pt_contents},\r
-       {"slime",       CONTENTS_SLIME, pt_contents},           // mildly damaging\r
-       {"lava",        CONTENTS_LAVA, pt_contents},            // very damaging\r
-       {"window",      CONTENTS_WINDOW, pt_contents},  // solid, but doesn't eat internal textures\r
-       {"mist",        CONTENTS_MIST, pt_contents},    // non-solid window\r
-       {"origin",      CONTENTS_ORIGIN, pt_contents},  // center of rotating brushes\r
-       {"playerclip",  CONTENTS_PLAYERCLIP, pt_contents},\r
-       {"monsterclip", CONTENTS_MONSTERCLIP, pt_contents},\r
-\r
-       // utility surface attributes\r
-       {"hint",        SURF_HINT, pt_flags},\r
-       {"skip",        SURF_SKIP, pt_flags},\r
-       {"light",       SURF_LIGHT, pt_flagvalue},              // value is the light quantity\r
-\r
-       {"animspeed",SURF_ANIMSPEED, pt_flagvalue},             // value will hold the anim speed in fps\r
-\r
-       // texture chaining\r
-       {"anim",        0,                      pt_animvalue},          // animname is the next animation\r
-       {"alt",         0,                      pt_altnamevalue},       // altname is the alternate texture\r
-       {"damage",      0,                      pt_damagenamevalue},    // damagename is the damage texture\r
-       {"scale",       0,                      pt_scale},              // next two values are for scale\r
-       {"mip",         0,                      pt_mip},                \r
-       {"detail",      0,                      pt_detail},             \r
-\r
-       {"GL_ZERO",                                     GL_ZERO,                                pt_gl},\r
-       {"GL_ONE",                                      GL_ONE,                                 pt_gl},\r
-       {"GL_SRC_COLOR",                        GL_SRC_COLOR,                   pt_gl},\r
-       {"GL_ONE_MINUS_SRC_COLOR",      GL_ONE_MINUS_SRC_COLOR, pt_gl},\r
-       {"GL_DST_COLOR",                        GL_DST_COLOR,                   pt_gl},\r
-       {"GL_ONE_MINUS_DST_COLOR",      GL_ONE_MINUS_DST_COLOR, pt_gl},\r
-       {"GL_SRC_ALPHA",                        GL_SRC_ALPHA,                   pt_gl},\r
-       {"GL_ONE_MINUS_SRC_ALPHA",      GL_ONE_MINUS_SRC_ALPHA, pt_gl},\r
-       {"GL_DST_ALPHA",                        GL_DST_ALPHA,                   pt_gl},\r
-       {"GL_ONE_MINUS_DST_ALPHA",      GL_ONE_MINUS_DST_ALPHA, pt_gl},\r
-       {"GL_SRC_ALPHA_SATURATE",       GL_SRC_ALPHA_SATURATE,  pt_gl},\r
-\r
-       // server attributes\r
-       {"slick",       SURF_SLICK, pt_flags},\r
-\r
-       // drawing attributes\r
-       {"sky",         SURF_SKY, pt_flags},\r
-       {"warping",     SURF_WARP, pt_flags},           // only valid with 64x64 textures\r
-       {"trans33",     SURF_TRANS33, pt_flags},        // translucent should allso set fullbright\r
-       {"trans66",     SURF_TRANS66, pt_flags},\r
-       {"flowing",     SURF_FLOWING, pt_flags},        // flow direction towards angle 0\r
-       {"nodraw",      SURF_NODRAW, pt_flags}, // for clip textures and trigger textures\r
-       {"alpha",       SURF_ALPHA_TEXTURE, pt_flags},\r
-       {"undulate",    SURF_UNDULATE, pt_flags},               // rock surface up and down...\r
-       {"skyreflect",  SURF_SKYREFLECT, pt_flags},             // liquid will somewhat reflect the sky - not quite finished....\r
-\r
-       {"material", SURF_MATERIAL, pt_materialvalue},\r
-       {"metal",       SURF_TYPE_METAL, pt_flags},\r
-       {"stone",       SURF_TYPE_STONE, pt_flags},\r
-       {"wood",        SURF_TYPE_WOOD, pt_flags},\r
-\r
-       {"m_nomip", 0, pt_nomip},\r
-       {"m_detail", 0, pt_detailer},\r
-\r
-       {NULL, 0, pt_contents}\r
-};\r
-\r
-/*\r
-==============\r
-Cmd_Mip\r
-\r
-$mip filename x y width height <OPTIONS>\r
-must be multiples of sixteen\r
-SURF_WINDOW\r
-==============\r
-*/\r
-\r
-void Cmd_Mip (void)\r
-{\r
-       int             xl,yl,xh,yh,w,h;\r
-       byte            *dest, *source;\r
-       int                             flags, value, contents;\r
-       mipparm_t               *mp;\r
-       char                    lumpname[128];\r
-       char                    altname[128];\r
-       char                    animname[128];\r
-       char                    damagename[128];\r
-       byte                    buffer[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE];\r
-       unsigned                bufferl[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE];\r
-       materialtype_t  *mat;\r
-       char                    filename[1024];\r
-       unsigned        *destl, *sourcel;\r
-       int             linedelta, x, y;\r
-       int                             size;\r
-       miptex_t                *qtex;\r
-       miptex32_t              *qtex32;\r
-       float                   scale_x, scale_y;\r
-       int                             mip_scale;\r
-       // detail texturing\r
-       char                    dt_name[128];\r
-       float                   dt_scale_x, dt_scale_y;\r
-       float                   dt_u, dt_v;\r
-       float                   dt_alpha;\r
-       int                             dt_src_blend_mode, dt_dst_blend_mode;\r
-       int                             flags2;\r
-\r
-\r
-       GetScriptToken (false);\r
-       strcpy (lumpname, token);\r
-       \r
-       GetScriptToken (false);\r
-       xl = atoi (token);\r
-       GetScriptToken (false);\r
-       yl = atoi (token);\r
-       GetScriptToken (false);\r
-       w = atoi (token);\r
-       GetScriptToken (false);\r
-       h = atoi (token);\r
-\r
-       total_x += w;\r
-       total_y += h;\r
-       total_textures++;\r
-\r
-       if ( (w & 15) || (h & 15) )\r
-               Error ("line %i: miptex sizes must be multiples of 16", scriptline);\r
-\r
-       flags = 0;\r
-       flags2 = 0;\r
-       contents = 0;\r
-       value = 0;\r
-       mip_scale = 0;\r
-\r
-       altname[0] = animname[0] = damagename[0] = 0;\r
-\r
-       scale_x = scale_y = 0.5;\r
-\r
-       // detail texturing\r
-       dt_name[0] = 0;\r
-       dt_scale_x = dt_scale_y = 0.0;\r
-       dt_u = dt_v = 0.0;\r
-       dt_alpha = 0.0;\r
-       dt_src_blend_mode = dt_dst_blend_mode = 0;\r
-\r
-       // get optional flags and values\r
-       while (ScriptTokenAvailable ())\r
-       {\r
-               GetScriptToken (false);\r
-       \r
-               for (mp=mipparms ; mp->name ; mp++)\r
-               {\r
-                       if (!strcmp(mp->name, token))\r
-                       {\r
-                               switch (mp->type)\r
-                               {\r
-                                       case pt_animvalue:\r
-                                               GetScriptToken (false); // specify the next animation frame\r
-                                               strcpy (animname, token);\r
-                                               break;\r
-                                       case pt_altnamevalue:\r
-                                               GetScriptToken (false); // specify the alternate texture\r
-                                               strcpy (altname, token);\r
-                                               break;\r
-                                       case pt_damagenamevalue:\r
-                                               GetScriptToken (false); // specify the damage texture\r
-                                               strcpy (damagename, token);\r
-                                               break;\r
-                                       case pt_flags:\r
-                                               flags |= mp->flags;\r
-                                               break;\r
-                                       case pt_contents:\r
-                                               contents |= mp->flags;\r
-                                               break;\r
-                                       case pt_flagvalue:\r
-                                               flags |= mp->flags;\r
-                                               GetScriptToken (false); // specify the light value\r
-                                               value = atoi(token);\r
-                                               break;\r
-                                       case pt_materialvalue:\r
-                                               GetScriptToken(false);\r
-                                               for (mat=materialtypes ; mat->name ; mat++)\r
-                                               {\r
-                                                       if (!strcmp(mat->name, token))\r
-                                                       {\r
-                                                               // assumes SURF_MATERIAL is in top 8 bits\r
-                                                               flags = (flags & 0x0FFFFFF) | (mat->value << 24);\r
-                                                               break;\r
-                                                       }\r
-                                               }\r
-                                               break;\r
-                                       case pt_scale:\r
-                                               GetScriptToken (false); // specify the x scale\r
-                                               scale_x = atof(token);\r
-                                               GetScriptToken (false); // specify the y scale\r
-                                               scale_y = atof(token);\r
-                                               break;\r
-\r
-                                       case pt_mip:\r
-                                               mip_scale = 1;\r
-                                               break;\r
-\r
-                                       case pt_detailer:\r
-                                               flags2 |= MIP32_DETAILER_FLAG2;\r
-                                               break;\r
-\r
-                                       case pt_nomip:\r
-                                               flags2 |= MIP32_NOMIP_FLAG2;\r
-                                               break;\r
-\r
-                                       case pt_detail:\r
-                                               GetScriptToken(false);\r
-                                               strcpy(dt_name, token);\r
-                                               GetScriptToken(false);\r
-                                               dt_scale_x = atof(token);\r
-                                               GetScriptToken(false);\r
-                                               dt_scale_y = atof(token);\r
-                                               GetScriptToken(false);\r
-                                               dt_u = atof(token);\r
-                                               GetScriptToken(false);\r
-                                               dt_v = atof(token);\r
-                                               GetScriptToken(false);\r
-                                               dt_alpha = atof(token);\r
-                                               GetScriptToken(false);\r
-                                               for (mp=mipparms ; mp->name ; mp++)\r
-                                               {\r
-                                                       if (!strcmp(mp->name, token))\r
-                                                       {\r
-                                                               if (mp->type == pt_gl)\r
-                                                               {\r
-                                                                       dt_src_blend_mode = mp->flags;\r
-                                                                       break;\r
-                                                               }\r
-                                                       }\r
-                                               }\r
-                                               if (!mp->name)\r
-                                               {\r
-                                                       Error ("line %i: invalid gl blend mode %s", scriptline, token);\r
-                                               }\r
-                                               GetScriptToken (false);\r
-                                               for (mp=mipparms ; mp->name ; mp++)\r
-                                               {\r
-                                                       if (!strcmp(mp->name, token))\r
-                                                       {\r
-                                                               if (mp->type == pt_gl)\r
-                                                               {\r
-                                                                       dt_dst_blend_mode = mp->flags;\r
-                                                                       break;\r
-                                                               }\r
-                                                       }\r
-                                               }\r
-                                               if (!mp->name)\r
-                                               {\r
-                                                       Error ("line %i: invalid gl blend mode %s", scriptline, token);\r
-                                               }\r
-                                               break;\r
-                               }\r
-                               break;\r
-                       }\r
-               }\r
-               if (!mp->name)\r
-                       Error ("line %i: unknown parm %s", scriptline, token);\r
-       }\r
-\r
-       if (g_release)\r
-               return; // textures are only released by $maps\r
-\r
-       xh = xl+w;\r
-       yh = yl+h;\r
-       if (xh*yh > MAX_IMAGE_SIZE*MAX_IMAGE_SIZE)\r
-       {\r
-               Error("line %i image %s: image is too big!", scriptline, lumpname);\r
-       }\r
-               \r
-       if (TrueColorImage)\r
-       {\r
-               if (xl >= longimagewidth || xh > longimagewidth ||\r
-                       yl >= longimageheight || yh > longimageheight)\r
-               {\r
-                       Error ("line %i image %s: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, lumpname, xl,yl,w,h,longimagewidth,longimageheight);\r
-               }\r
-\r
-               sourcel = longimage + (yl*longimagewidth) + xl;\r
-               destl = bufferl;\r
-               linedelta = (longimagewidth - w);\r
-\r
-               for (y=yl ; y<yh ; y++)\r
-               {\r
-                       for (x=xl ; x<xh ; x++)\r
-                       {\r
-                               *destl++ = *sourcel++;  // RGBA\r
-                       }\r
-                       sourcel += linedelta;\r
-               }\r
-\r
-               qtex32 = CreateMip32(bufferl, w, h, &size, true);\r
-\r
-               qtex32->flags |= LittleLong(flags);\r
-               qtex32->flags2 |= LittleLong(flags2);\r
-               qtex32->contents = LittleLong(contents);\r
-               qtex32->value = LittleLong(value);\r
-               qtex32->scale_x = scale_x;\r
-               qtex32->scale_y = scale_y;\r
-               qtex32->mip_scale = mip_scale;\r
-               sprintf (qtex32->name, "%s/%s", mip_prefix, lumpname);\r
-               if (animname[0])\r
-               {\r
-                       sprintf (qtex32->animname, "%s/%s", mip_prefix, animname);\r
-               }\r
-               if (altname[0])\r
-               {\r
-                       sprintf (qtex32->altname, "%s/%s", mip_prefix, altname);\r
-               }\r
-               if (damagename[0])\r
-               {\r
-                       sprintf (qtex32->damagename, "%s/%s", mip_prefix, damagename);\r
-               }\r
-               if (dt_name[0] & ((flags2 & MIP32_DETAILER_FLAG2) == 0)) \r
-               {\r
-                       sprintf (qtex32->dt_name, "%s/%s", mip_prefix, dt_name);\r
-                       qtex32->dt_scale_x = dt_scale_x;\r
-                       qtex32->dt_scale_y = dt_scale_y;\r
-                       qtex32->dt_u = dt_u;\r
-                       qtex32->dt_v = dt_v;\r
-                       qtex32->dt_alpha = dt_alpha;\r
-                       qtex32->dt_src_blend_mode = dt_src_blend_mode;\r
-                       qtex32->dt_dst_blend_mode = dt_dst_blend_mode;\r
-               }\r
-               \r
-       //\r
-       // write it out\r
-       //\r
-               sprintf (filename, "%stextures/%s/%s.m32", g_outputDir, mip_prefix, lumpname);\r
-               if(qtex32->flags & (SURF_ALPHA_TEXTURE))\r
-                       printf ("writing %s with ALPHA\n", filename);\r
-               else\r
-                       printf ("writing %s\n", filename);\r
-               SaveFile (filename, (byte *)qtex32, size);\r
-\r
-               free (qtex32);\r
-       }\r
-       else\r
-       {\r
-               if (xl >= byteimagewidth || xh > byteimagewidth ||\r
-                       yl >= byteimageheight || yh > byteimageheight)\r
-               {\r
-                       Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,byteimagewidth,byteimageheight);\r
-               }\r
-\r
-               source = byteimage + yl*byteimagewidth + xl;\r
-               dest = buffer;\r
-               linedelta = byteimagewidth - w;\r
-\r
-               for (y=yl ; y<yh ; y++)\r
-               {\r
-                       for (x=xl ; x<xh ; x++)\r
-                       {\r
-                               *dest++ = *source++;\r
-                       }\r
-                       source += linedelta;\r
-               }\r
-\r
-               qtex = CreateMip(buffer, w, h, lbmpalette, &size, true);\r
-\r
-               qtex->flags = LittleLong(flags);\r
-               qtex->contents = LittleLong(contents);\r
-               qtex->value = LittleLong(value);\r
-               sprintf (qtex->name, "%s/%s", mip_prefix, lumpname);\r
-               if (animname[0])\r
-                       sprintf (qtex->animname, "%s/%s", mip_prefix, animname);\r
-               \r
-       //\r
-       // write it out\r
-       //\r
-               sprintf (filename, "%stextures/%s/%s.m8", g_outputDir, mip_prefix, lumpname);\r
-               printf ("writing %s\n", filename);\r
-               SaveFile (filename, (byte *)qtex, size);\r
-\r
-               free (qtex);\r
-       }\r
-}\r
-\r
-/*\r
-===============\r
-Cmd_Mippal\r
-===============\r
-*/\r
-void Cmd_Mippal (void)\r
-{\r
-       colormap_issued = true;\r
-       if (g_release)\r
-               return;\r
-\r
-       memcpy (colormap_palette, lbmpalette, 768);\r
-\r
-       BuildPalmap();\r
-}\r
-\r
-\r
-/*\r
-===============\r
-Cmd_Mipdir\r
-===============\r
-*/\r
-void Cmd_Mipdir (void)\r
-{\r
-       char    filename[1024];\r
-\r
-       GetScriptToken (false);\r
-       strcpy (mip_prefix, token);\r
-       // create the directory if needed\r
-       sprintf (filename, "%stextures", g_outputDir);\r
-       Q_mkdir (filename); \r
-       sprintf (filename, "%stextures/%s", g_outputDir, mip_prefix);\r
-       Q_mkdir (filename); \r
-}\r
-\r
-\r
-/*\r
-=============================================================================\r
-\r
-ENVIRONMENT MAP GRABBING\r
-\r
-Creates six pcx files from tga files without any palette edge seams\r
-also copies the tga files for GL rendering.\r
-=============================================================================\r
-*/\r
-\r
-// 3dstudio environment map suffixes\r
-char   *suf[6] = {"rt", "ft", "lf", "bk", "up", "dn"};\r
-\r
-/*\r
-=================\r
-Cmd_Environment\r
-=================\r
-*/\r
-void Cmd_Environment (void)\r
-{\r
-       char    name[1024];\r
-       int             i, x, y;\r
-       byte    image[256*256];\r
-       byte    *tga;\r
-\r
-       GetScriptToken (false);\r
-\r
-       if (g_release)\r
-       {\r
-               for (i=0 ; i<6 ; i++)\r
-               {\r
-                       sprintf (name, "env/%s%s.pcx", token, suf[i]);\r
-                       ReleaseFile (name);\r
-                       sprintf (name, "env/%s%s.tga", token, suf[i]);\r
-                       ReleaseFile (name);\r
-               }\r
-               return;\r
-       }\r
-       // get the palette\r
-       BuildPalmap ();\r
-\r
-       sprintf (name, "%senv/", gamedir);\r
-       CreatePath (name);\r
-\r
-       // convert the images\r
-       for (i=0 ; i<6 ; i++)\r
-       {\r
-               sprintf (name, "%senv/%s%s.tga", gamedir, token, suf[i]);\r
-               printf ("loading %s...\n", name);\r
-               LoadTGA (name, &tga, NULL, NULL);\r
-\r
-               for (y=0 ; y<256 ; y++)\r
-               {\r
-                       for (x=0 ; x<256 ; x++)\r
-                       {\r
-                               image[y*256+x] = FindColor (tga[(y*256+x)*4+0],tga[(y*256+x)*4+1],tga[(y*256+x)*4+2]);\r
-                       }\r
-               }\r
-               free (tga);\r
-               sprintf (name, "%senv/%s%s.pcx", gamedir, token, suf[i]);\r
-               if (FileTime (name) != -1)\r
-                       printf ("%s already exists, not overwriting.\n", name);\r
-               else\r
-                       WritePCXfile (name, image, 256, 256, colormap_palette);\r
-       }\r
-}\r
-\r
+/*
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include "qdata.h"
+
+#ifdef _WIN32
+ #include <windows.h>
+#endif
+
+#include <GL/gl.h>
+
+#if 1
+       extern char             *g_outputDir;
+#endif // _QDATA
+
+char           mip_prefix[1024];               // directory to dump the textures in
+
+qboolean       colormap_issued;
+byte           colormap_palette[768];
+
+unsigned total_x = 0;
+unsigned total_y = 0;
+unsigned total_textures = 0;
+
+#define MAX_IMAGE_SIZE 512
+
+#if    0
+/*
+==============
+RemapZero
+
+Replaces all 0 bytes in an image with the closest palette entry.
+This is because NT won't let us change index 0, so any palette
+animation leaves those pixels untouched.
+==============
+*/
+void RemapZero (byte *pixels, byte *palette, int width, int height)
+{
+       int             i, c;
+       int             alt_zero;
+       int             value, best;
+
+       alt_zero = 0;
+       best = 9999999;
+       for (i=1 ; i<255 ; i++)
+       {
+               value = palette[i*3+0]+palette[i*3+1]+palette[i*3+2];
+               if (value < best)
+               {
+                       best = value;
+                       alt_zero = i;
+               }
+       }
+
+       c = width*height;
+       for (i=0 ; i<c ; i++)
+               if (pixels[i] == 0)
+                       pixels[i] = alt_zero;
+}
+
+#endif
+
+
+// ********************************************************************
+// **  Mip Map Pre-Processing Routines
+// ********************************************************************
+
+#define intensity_value 1
+
+static unsigned image_pal[256];
+
+#define MAX_LAST 25
+
+long palette_r[256], palette_g[256], palette_b[256];
+long last_r[MAX_LAST],last_g[MAX_LAST],last_b[MAX_LAST], last_i[MAX_LAST], last_place;
+
+long cached;
+
+void PrepareConvert(unsigned *palette)
+{
+       int i;
+
+       for(i=0;i<256;i++)
+       {
+               palette_r[i] = (palette[i] & 0x00ff0000) >> 16;
+               palette_g[i] = (palette[i] & 0x0000ff00) >> 8;
+               palette_b[i] = (palette[i] & 0x000000ff);
+       }
+
+       for(i=0;i<MAX_LAST;i++)
+               last_r[i] = -1;
+
+       last_place = -1;
+}
+
+int ConvertTrueColorToPal(unsigned r, unsigned g, unsigned b)
+{
+       int i;
+       long min_dist;
+       int min_index;
+       long dist;
+       long dr, dg, db, biggest_delta;
+
+       for(i=0;i<MAX_LAST;i++)
+               if (r == last_r[i] && g == last_g[i] && b == last_b[i])
+               {
+                       cached++;
+                       return last_i[i];
+               }
+
+       min_dist = 256 * 256 + 256 * 256 + 256 * 256;
+       biggest_delta = 256*256;
+       min_index = 0;
+
+       for (i=0;i<256;i++)
+       {
+               dr = abs(palette_r[i] - r);
+               if (dr > biggest_delta)
+                       continue;
+               dg = abs(palette_g[i] - g);
+               if (dg > biggest_delta)
+                       continue;
+               db = abs(palette_b[i] - b);
+               if (db > biggest_delta)
+                       continue;
+
+               dist = dr * dr + dg * dg + db * db;
+               if (dist < min_dist)
+               {
+                       min_dist = dist;
+                       min_index = i;
+                       if (min_dist == 0) break;
+
+                       dist = dr;
+                       if (dg > dist) dist = dg;
+                       if (db > dist) dist = db;
+                       if (dist < biggest_delta)
+                               biggest_delta = dist;
+               }
+       }
+
+       last_place++;
+       if (last_place >= MAX_LAST)
+               last_place = 0;
+
+       last_r[last_place] = r;
+       last_g[last_place] = g;
+       last_b[last_place] = b;
+       last_i[last_place] = min_index;
+
+       return min_index;
+}
+
+
+void GL_ResampleTexture8P (byte *in, int inwidth, int inheight, byte *out,  
+                                                  int outwidth, int outheight, palette_t *palette)
+{
+       int             i, j;
+       byte    *inrow, *inrow2;
+       unsigned        frac, fracstep;
+       unsigned        p1[1024], p2[1024], *p1p, *p2p;
+       palette_t       *c1,*c2,*c3,*c4;
+       unsigned        r,g,b;
+       
+       fracstep = inwidth*0x10000/outwidth;
+
+       frac = fracstep>>2;
+       for (i=0 ; i<outwidth ; i++)
+       {
+               p1[i] = frac>>16;
+               frac += fracstep;
+       }
+       frac = 3*(fracstep>>2);
+       for (i=0 ; i<outwidth ; i++)
+       {
+               p2[i] = frac>>16;
+               frac += fracstep;
+       }
+
+       cached = 0;
+       
+       for (i=0 ; i<outheight ; i++)//, out += outwidth)
+       {
+               inrow = in + inwidth*(int)((i+0.25)*inheight/outheight);
+               inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight);
+
+               p1p = p1;
+               p2p = p2;
+               for (j=0 ; j<outwidth ; j++)
+               {
+                       c1 = &palette[*((byte *)inrow + (*p1p))];
+                       c2 = &palette[*((byte *)inrow + (*p2p))];
+                       c3 = &palette[*((byte *)inrow2 + (*p1p++))];
+                       c4 = &palette[*((byte *)inrow2 + (*p2p++))];
+
+                       r = ((unsigned)c1->r + (unsigned)c2->r + (unsigned)c3->r + (unsigned)c4->r)>>2;
+                       g = ((unsigned)c1->g + (unsigned)c2->g + (unsigned)c3->g + (unsigned)c4->g)>>2;
+                       b = ((unsigned)c1->b + (unsigned)c2->b + (unsigned)c3->b + (unsigned)c4->b)>>2;
+
+                       *out++ = ConvertTrueColorToPal(r,g,b);
+               }
+       }
+}
+
+void GL_MipMap8P(byte *out, byte *in, int width, int height, palette_t *palette)
+{
+       int                     i, j;
+       palette_t       *c1,*c2,*c3,*c4;
+       unsigned        r,g,b;
+
+       cached = 0;
+       memset(out, 0, 256 * 256);
+       width <<= 1;
+       height <<= 1;
+
+       for (i = 0; i < height; i += 2, in += width)
+       {
+               for (j = 0; j < width; j += 2)
+               {
+                       c1 = &palette[in[0]];
+                       c3 = &palette[in[width]];
+                       in++;
+                       c2 = &palette[in[0]];
+                       c4 = &palette[in[width]];
+                       in++;
+
+                       r = ((unsigned)c1->r + (unsigned)c2->r + (unsigned)c3->r + (unsigned)c4->r) >> 2;
+                       g = ((unsigned)c1->g + (unsigned)c2->g + (unsigned)c3->g + (unsigned)c4->g) >> 2;
+                       b = ((unsigned)c1->b + (unsigned)c2->b + (unsigned)c3->b + (unsigned)c4->b) >> 2;
+
+                       *out++ = ConvertTrueColorToPal(r, g, b);
+               }
+       }
+}
+
+
+miptex_t *CreateMip(byte *data, unsigned width, unsigned height, byte *palette, int *FinalSize, qboolean mip)
+{
+       int                     scaled_width, scaled_height;
+       int                     i,j,r,g,b;
+       byte            intensitytable[256];
+       byte            scaled[256*256];
+       byte            out[256*256];
+       int                     miplevel;
+       miptex_t        *mp;
+       byte            *pos;
+       int                     size;
+
+       for (i=0 ; i<256 ; i++)
+       {
+               j = i * intensity_value;
+               if (j > 255)
+                       j = 255;
+               intensitytable[i] = j;
+       }
+
+       for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
+               ;
+       if (1 && scaled_width > width && 1)
+               scaled_width >>= 1;
+       for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
+               ;
+       if (1 && scaled_height > height && 1)
+               scaled_height >>= 1;
+
+       // don't ever bother with >256 textures
+       if (scaled_width > 256)
+               scaled_width = 256;
+       if (scaled_height > 256)
+               scaled_height = 256;
+
+       if (scaled_width < 1)
+               scaled_width = 1;
+       if (scaled_height < 1)
+               scaled_height = 1;
+
+       size = sizeof(*mp) + (scaled_width*scaled_height*3);
+       mp = (miptex_t *)SafeMalloc(size, "CreateMip");
+       memset(mp,0,size);
+
+       mp->version = MIP_VERSION;
+
+       for(i=j=0;i<256;i++,j+=3)
+       {
+               mp->palette[i].r = r = intensitytable[palette[j]];
+               mp->palette[i].g = g = intensitytable[palette[j+1]];
+               mp->palette[i].b = b = intensitytable[palette[j+2]];
+               image_pal[i] = 0xff000000 | (r<<16) | (g<<8) | (b);
+       }
+
+       PrepareConvert(image_pal);
+
+       if (scaled_width == width && scaled_height == height)
+       {
+               memcpy (scaled, data, width*height);
+       }
+       else
+               GL_ResampleTexture8P (data, width, height, scaled, scaled_width, scaled_height, mp->palette);
+
+       pos = (byte *)(mp + 1);
+       miplevel = 0;
+
+       while ((scaled_width >= 1 || scaled_height >= 1) && (miplevel <= MIPLEVELS-1) && (!miplevel || mip))
+       {
+               if (scaled_width < 1)
+                       scaled_width = 1;
+               if (scaled_height < 1)
+                       scaled_height = 1;
+
+               if(miplevel > 0)
+                       GL_MipMap8P(out, (byte *)scaled, scaled_width, scaled_height, mp->palette);
+               else
+                       memcpy(out, scaled, 256 * 256);
+
+               mp->width[miplevel] = scaled_width;
+               mp->height[miplevel] = scaled_height;
+               mp->offsets[miplevel] = pos - ((byte *)(mp));
+               memcpy(pos, out, scaled_width * scaled_height);
+               memcpy(scaled, out, 256 * 256);
+               pos += scaled_width * scaled_height;
+
+               scaled_width >>= 1;
+               scaled_height >>= 1;
+
+               miplevel++;
+       }
+
+       *FinalSize = pos - ((byte *)(mp));
+
+       return mp;
+}
+
+
+void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out,  int outwidth, int outheight)
+{
+       int             i, j;
+       unsigned        *inrow, *inrow2;
+       unsigned        frac, fracstep;
+       unsigned        p1[1024], p2[1024];
+       byte            *pix1, *pix2, *pix3, *pix4;
+
+       fracstep = inwidth*0x10000/outwidth;
+
+       frac = fracstep>>2;
+       for (i=0 ; i<outwidth ; i++)
+       {
+               p1[i] = 4*(frac>>16);
+               frac += fracstep;
+       }
+       frac = 3*(fracstep>>2);
+       for (i=0 ; i<outwidth ; i++)
+       {
+               p2[i] = 4*(frac>>16);
+               frac += fracstep;
+       }
+
+       for (i=0 ; i<outheight ; i++, out += outwidth)
+       {
+               inrow = in + inwidth*(int)((i+0.25)*inheight/outheight);
+               inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight);
+               frac = fracstep >> 1;
+               for (j=0 ; j<outwidth ; j++)
+               {
+                       pix1 = (byte *)inrow + p1[j];
+                       pix2 = (byte *)inrow + p2[j];
+                       pix3 = (byte *)inrow2 + p1[j];
+                       pix4 = (byte *)inrow2 + p2[j];
+                       ((byte *)(out+j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>2;
+                       ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2;
+                       ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2;
+                       ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2;
+               }
+       }
+}
+
+void GL_MipMap (byte *out, byte *in, int width, int height)
+{
+       int             i, j;
+
+       width <<=3;
+       height <<= 1;
+       for (i=0 ; i<height ; i++, in+=width)
+       {
+               for (j=0 ; j<width ; j+=8, out+=4, in+=8)
+               {
+                       out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>2;
+                       out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2;
+                       out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2;
+                       out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2;
+               }
+       }
+}
+
+miptex32_t *CreateMip32(unsigned *data, unsigned width, unsigned height, int *FinalSize, qboolean mip)
+{
+       int                             scaled_width, scaled_height;
+       unsigned                scaled[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE];
+       unsigned                out[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE];
+       int                             miplevel;
+       miptex32_t              *mp;
+       byte                    *pos;
+       int                             size;
+       paletteRGBA_t   *test;
+
+       for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
+               ;
+       if (1 && scaled_width > width && 1)
+               scaled_width >>= 1;
+       for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
+               ;
+       if (1 && scaled_height > height && 1)
+               scaled_height >>= 1;
+
+       // don't ever bother with >256 textures
+       if (scaled_width > MAX_IMAGE_SIZE)
+               scaled_width = MAX_IMAGE_SIZE;
+       if (scaled_height > MAX_IMAGE_SIZE)
+               scaled_height = MAX_IMAGE_SIZE;
+
+       if (scaled_width < 1)
+               scaled_width = 1;
+       if (scaled_height < 1)
+               scaled_height = 1;
+
+       size = sizeof(*mp) + (scaled_width*scaled_height*3*4);
+       mp = (miptex32_t *)SafeMalloc(size, "CreateMip");
+       memset(mp,0,size);
+
+       mp->version = MIP32_VERSION;
+
+       size = width*height;
+       test = (paletteRGBA_t *)data;
+       while(size)
+       {
+               if (test->a != 255)
+               {
+                       mp->flags |= LittleLong(SURF_ALPHA_TEXTURE);
+                       break;
+               }
+
+               size--;
+               test++;
+       }
+
+       if (scaled_width == width && scaled_height == height)
+       {
+               memcpy (scaled, data, width*height*4);
+       }
+       else
+               GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);
+
+       pos = (byte *)(mp + 1);
+       miplevel = 0;
+
+       while ((scaled_width >= 1 || scaled_height >= 1) && (miplevel <= MIPLEVELS-1) && (!miplevel || mip))
+       {
+               if (scaled_width < 1)
+                       scaled_width = 1;
+               if (scaled_height < 1)
+                       scaled_height = 1;
+
+               if (miplevel > 0)
+               {
+                       GL_MipMap((byte *)out, (byte *)scaled, scaled_width, scaled_height);
+               }
+               else
+               {
+                       memcpy(out, scaled, MAX_IMAGE_SIZE * MAX_IMAGE_SIZE * 4);
+               }
+
+               mp->width[miplevel] = scaled_width;
+               mp->height[miplevel] = scaled_height;
+               mp->offsets[miplevel] = pos - ((byte *)(mp));
+               memcpy(pos, out, scaled_width * scaled_height * 4);
+               memcpy(scaled, out, MAX_IMAGE_SIZE * MAX_IMAGE_SIZE * 4);
+               pos += scaled_width * scaled_height * 4;
+
+               scaled_width >>= 1;
+               scaled_height >>= 1;
+
+               miplevel++;
+       }
+
+       *FinalSize = pos - ((byte *)(mp));
+
+       return mp;
+}
+
+/*
+==============
+Cmd_Grab
+
+$grab filename x y width height
+==============
+*/
+void Cmd_Grab (void)
+{
+       int             xl,yl,w,h,y;
+       byte                    *cropped;
+       char                    savename[1024];
+       char                    dest[1024];
+
+       GetScriptToken (false);
+
+       if (token[0] == '/' || token[0] == '\\')
+               sprintf (savename, "%s%s.pcx", gamedir, token+1);
+       else
+               sprintf (savename, "%spics/%s.pcx", gamedir, token);
+
+       if (g_release)
+       {
+               if (token[0] == '/' || token[0] == '\\')
+                       sprintf (dest, "%s.pcx", token+1);
+               else
+                       sprintf (dest, "pics/%s.pcx", token);
+
+               ReleaseFile (dest);
+               return;
+       }
+
+       GetScriptToken (false);
+       xl = atoi (token);
+       GetScriptToken (false);
+       yl = atoi (token);
+       GetScriptToken (false);
+       w = atoi (token);
+       GetScriptToken (false);
+       h = atoi (token);
+
+       if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight)
+               Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h);
+
+       // crop it to the proper size
+       cropped = (byte *) SafeMalloc (w*h, "Cmd_Grab");
+       for (y=0 ; y<h ; y++)
+       {
+               memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);
+       }
+
+       // save off the new image
+       printf ("saving %s\n", savename);
+       CreatePath (savename);
+       WritePCXfile (savename, cropped, w,     h, lbmpalette);
+
+       free (cropped);
+}
+
+/*
+==============
+Cmd_Raw
+
+$grab filename x y width height
+==============
+*/
+void Cmd_Raw (void)
+{
+       int             xl,yl,w,h,y;
+       byte                    *cropped;
+       char                    savename[1024];
+       char                    dest[1024];
+
+       GetScriptToken (false);
+
+       sprintf (savename, "%s%s.lmp", gamedir, token);
+
+       if (g_release)
+       {
+               sprintf (dest, "%s.lmp", token);
+               ReleaseFile (dest);
+               return;
+       }
+
+       GetScriptToken (false);
+       xl = atoi (token);
+       GetScriptToken (false);
+       yl = atoi (token);
+       GetScriptToken (false);
+       w = atoi (token);
+       GetScriptToken (false);
+       h = atoi (token);
+
+       if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight)
+               Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h);
+
+       // crop it to the proper size
+       cropped = (byte *) SafeMalloc (w*h, "Cmd_Raw");
+       for (y=0 ; y<h ; y++)
+       {
+               memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);
+       }
+
+       // save off the new image
+       printf ("saving %s\n", savename);
+       CreatePath (savename);
+
+       SaveFile (savename, cropped, w*h);
+
+       free (cropped);
+}
+
+/*
+=============================================================================
+
+COLORMAP GRABBING
+
+=============================================================================
+*/
+
+/*
+===============
+BestColor
+===============
+*/
+byte BestColor (int r, int g, int b, int start, int stop)
+{
+       int     i;
+       int     dr, dg, db;
+       int     bestdistortion, distortion;
+       int     bestcolor;
+       byte    *pal;
+
+//
+// let any color go to 0 as a last resort
+//
+       bestdistortion = 256*256*4;
+       bestcolor = 0;
+
+       pal = colormap_palette + start*3;
+       for (i=start ; i<= stop ; i++)
+       {
+               dr = r - (int)pal[0];
+               dg = g - (int)pal[1];
+               db = b - (int)pal[2];
+               pal += 3;
+               distortion = dr*dr + dg*dg + db*db;
+               if (distortion < bestdistortion)
+               {
+                       if (!distortion)
+                               return i;               // perfect match
+
+                       bestdistortion = distortion;
+                       bestcolor = i;
+               }
+       }
+
+       return bestcolor;
+}
+
+
+/*
+==============
+Cmd_Colormap
+
+$colormap filename
+
+  the brightes colormap is first in the table (FIXME: reverse this now?)
+
+  64 rows of 256 : lightmaps
+  256 rows of 256 : translucency table
+==============
+*/
+void Cmd_Colormap (void)
+{
+       int             levels, brights;
+       int             l, c;
+       float   frac, red, green, blue;
+       float   range;
+       byte    *cropped, *lump_p;
+       char    savename[1024];
+       char    dest[1024];
+
+       colormap_issued = true;
+       if (!g_release)
+               memcpy (colormap_palette, lbmpalette, 768);
+
+       if (!ScriptTokenAvailable ())
+       {       // just setting colormap_issued
+               return;
+       }
+
+       GetScriptToken (false);
+       sprintf (savename, "%spics/%s.pcx", gamedir, token);
+
+       if (g_release)
+       {
+               sprintf (dest, "pics/%s.pcx", token);
+               ReleaseFile (dest);
+               return;
+       }
+
+       range = 2;
+       levels = 64;
+       brights = 1;    // ignore 255 (transparent)
+
+       cropped = (byte *) SafeMalloc((levels+256)*256, "Cmd_ColorMap");
+       lump_p = cropped;
+
+// shaded levels
+       for (l=0;l<levels;l++)
+       {
+               frac = range - range*(float)l/(levels-1);
+               for (c=0 ; c<256-brights ; c++)
+               {
+                       red = lbmpalette[c*3];
+                       green = lbmpalette[c*3+1];
+                       blue = lbmpalette[c*3+2];
+
+                       red = (int)(red*frac+0.5);
+                       green = (int)(green*frac+0.5);
+                       blue = (int)(blue*frac+0.5);
+                       
+//
+// note: 254 instead of 255 because 255 is the transparent color, and we
+// don't want anything remapping to that
+// don't use color 0, because NT can't remap that (or 255)
+//
+                       *lump_p++ = BestColor(red,green,blue, 1, 254);
+               }
+
+               // fullbrights allways stay the same
+               for ( ; c<256 ; c++)
+                       *lump_p++ = c;
+       }
+       
+// 66% transparancy table
+       for (l=0;l<255;l++)
+       {
+               for (c=0 ; c<255 ; c++)
+               {
+                       red = lbmpalette[c*3]*0.33 + lbmpalette[l*3]*0.66;
+                       green = lbmpalette[c*3+1]*0.33 + lbmpalette[l*3+1]*0.66;
+                       blue = lbmpalette[c*3+2]*0.33 + lbmpalette[l*3+2]*0.66;
+
+                       *lump_p++ = BestColor(red,green,blue, 1, 254);
+               }
+               *lump_p++ = 255;
+       }
+       for (c=0 ; c<256 ; c++)
+               *lump_p++ = 255;
+       
+       // save off the new image
+       printf ("saving %s\n", savename);
+       CreatePath (savename);
+       WritePCXfile (savename, cropped, 256, levels+256, lbmpalette);
+
+       free (cropped);
+}
+
+/*
+=============================================================================
+
+MIPTEX GRABBING
+
+=============================================================================
+*/
+
+byte   pixdata[256];
+
+int            d_red, d_green, d_blue;
+
+byte   palmap[32][32][32];
+qboolean       palmap_built;
+
+/*
+=============
+FindColor
+=============
+*/
+int FindColor (int r, int g, int b)
+{
+       int             bestcolor;
+
+       if (r > 255)
+               r = 255;
+       if (r < 0)
+               r = 0;
+       if (g > 255)
+               g = 255;
+       if (g < 0)
+               g = 0;
+       if (b > 255)
+               b = 255;
+       if (b < 0)
+               b = 0;
+#ifndef TABLECOLORS
+       bestcolor = BestColor (r, g, b, 0, 254);
+#else
+       bestcolor = palmap[r>>3][g>>3][b>>3];
+#endif
+
+       return bestcolor;
+}
+
+
+void BuildPalmap (void)
+{
+#ifdef TABLECOLORS
+       int             r, g, b;
+       int             bestcolor;
+
+       if (palmap_built)
+               return;
+       palmap_built = true;
+
+       for (r=4 ; r<256 ; r+=8)
+       {
+               for (g=4 ; g<256 ; g+=8)
+               {
+                       for (b=4 ; b<256 ; b+=8)
+                       {
+                               bestcolor = BestColor (r, g, b, 1, 254);
+                               palmap[r>>3][g>>3][b>>3] = bestcolor;
+                       }
+               }
+       }
+#endif
+
+       if (!colormap_issued)
+               Error ("You must issue a $colormap command first");
+
+}
+
+/*
+=============
+AveragePixels
+=============
+*/
+byte AveragePixels (int count)
+{
+       int             r,g,b;
+       int             i;
+       int             vis;
+       int             pix;
+       int             bestcolor;
+       byte    *pal;
+       int             fullbright;
+       
+       vis = 0;
+       r = g = b = 0;
+       fullbright = 0;
+       for (i=0 ; i<count ; i++)
+       {
+               pix = pixdata[i];
+               
+               r += lbmpalette[pix*3];
+               g += lbmpalette[pix*3+1];
+               b += lbmpalette[pix*3+2];
+               vis++;
+       }
+               
+       r /= vis;
+       g /= vis;
+       b /= vis;
+
+       // error diffusion
+       r += d_red;
+       g += d_green;
+       b += d_blue;
+       
+//
+// find the best color
+//
+       bestcolor = FindColor (r, g, b);
+
+       // error diffusion
+       pal = colormap_palette + bestcolor*3;
+       d_red = r - (int)pal[0];
+       d_green = g - (int)pal[1];
+       d_blue = b - (int)pal[2];
+
+       return bestcolor;
+}
+
+
+typedef enum
+{
+       pt_contents,
+       pt_flags,
+       pt_animvalue,
+       pt_altnamevalue,
+       pt_damagenamevalue,
+       pt_flagvalue,
+       pt_materialvalue,
+       pt_scale,
+       pt_mip,
+       pt_detail,
+       pt_gl,
+       pt_nomip,
+       pt_detailer,
+} parmtype_t;
+
+typedef struct
+{
+       char    *name;
+       int             flags;
+       parmtype_t      type;
+} mipparm_t;
+
+mipparm_t      mipparms[] =
+{
+       // utility content attributes
+       {"pushpull",CONTENTS_PUSHPULL, pt_contents},
+       {"water",       CONTENTS_WATER, pt_contents},
+       {"slime",       CONTENTS_SLIME, pt_contents},           // mildly damaging
+       {"lava",        CONTENTS_LAVA, pt_contents},            // very damaging
+       {"window",      CONTENTS_WINDOW, pt_contents},  // solid, but doesn't eat internal textures
+       {"mist",        CONTENTS_MIST, pt_contents},    // non-solid window
+       {"origin",      CONTENTS_ORIGIN, pt_contents},  // center of rotating brushes
+       {"playerclip",  CONTENTS_PLAYERCLIP, pt_contents},
+       {"monsterclip", CONTENTS_MONSTERCLIP, pt_contents},
+
+       // utility surface attributes
+       {"hint",        SURF_HINT, pt_flags},
+       {"skip",        SURF_SKIP, pt_flags},
+       {"light",       SURF_LIGHT, pt_flagvalue},              // value is the light quantity
+
+       {"animspeed",SURF_ANIMSPEED, pt_flagvalue},             // value will hold the anim speed in fps
+
+       // texture chaining
+       {"anim",        0,                      pt_animvalue},          // animname is the next animation
+       {"alt",         0,                      pt_altnamevalue},       // altname is the alternate texture
+       {"damage",      0,                      pt_damagenamevalue},    // damagename is the damage texture
+       {"scale",       0,                      pt_scale},              // next two values are for scale
+       {"mip",         0,                      pt_mip},                
+       {"detail",      0,                      pt_detail},             
+
+       {"GL_ZERO",                                     GL_ZERO,                                pt_gl},
+       {"GL_ONE",                                      GL_ONE,                                 pt_gl},
+       {"GL_SRC_COLOR",                        GL_SRC_COLOR,                   pt_gl},
+       {"GL_ONE_MINUS_SRC_COLOR",      GL_ONE_MINUS_SRC_COLOR, pt_gl},
+       {"GL_DST_COLOR",                        GL_DST_COLOR,                   pt_gl},
+       {"GL_ONE_MINUS_DST_COLOR",      GL_ONE_MINUS_DST_COLOR, pt_gl},
+       {"GL_SRC_ALPHA",                        GL_SRC_ALPHA,                   pt_gl},
+       {"GL_ONE_MINUS_SRC_ALPHA",      GL_ONE_MINUS_SRC_ALPHA, pt_gl},
+       {"GL_DST_ALPHA",                        GL_DST_ALPHA,                   pt_gl},
+       {"GL_ONE_MINUS_DST_ALPHA",      GL_ONE_MINUS_DST_ALPHA, pt_gl},
+       {"GL_SRC_ALPHA_SATURATE",       GL_SRC_ALPHA_SATURATE,  pt_gl},
+
+       // server attributes
+       {"slick",       SURF_SLICK, pt_flags},
+
+       // drawing attributes
+       {"sky",         SURF_SKY, pt_flags},
+       {"warping",     SURF_WARP, pt_flags},           // only valid with 64x64 textures
+       {"trans33",     SURF_TRANS33, pt_flags},        // translucent should allso set fullbright
+       {"trans66",     SURF_TRANS66, pt_flags},
+       {"flowing",     SURF_FLOWING, pt_flags},        // flow direction towards angle 0
+       {"nodraw",      SURF_NODRAW, pt_flags}, // for clip textures and trigger textures
+       {"alpha",       SURF_ALPHA_TEXTURE, pt_flags},
+       {"undulate",    SURF_UNDULATE, pt_flags},               // rock surface up and down...
+       {"skyreflect",  SURF_SKYREFLECT, pt_flags},             // liquid will somewhat reflect the sky - not quite finished....
+
+       {"material", SURF_MATERIAL, pt_materialvalue},
+       {"metal",       SURF_TYPE_METAL, pt_flags},
+       {"stone",       SURF_TYPE_STONE, pt_flags},
+       {"wood",        SURF_TYPE_WOOD, pt_flags},
+
+       {"m_nomip", 0, pt_nomip},
+       {"m_detail", 0, pt_detailer},
+
+       {NULL, 0, pt_contents}
+};
+
+/*
+==============
+Cmd_Mip
+
+$mip filename x y width height <OPTIONS>
+must be multiples of sixteen
+SURF_WINDOW
+==============
+*/
+
+void Cmd_Mip (void)
+{
+       int             xl,yl,xh,yh,w,h;
+       byte            *dest, *source;
+       int                             flags, value, contents;
+       mipparm_t               *mp;
+       char                    lumpname[128];
+       char                    altname[128];
+       char                    animname[128];
+       char                    damagename[128];
+       byte                    buffer[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE];
+       unsigned                bufferl[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE];
+       materialtype_t  *mat;
+       char                    filename[1024];
+       unsigned        *destl, *sourcel;
+       int             linedelta, x, y;
+       int                             size;
+       miptex_t                *qtex;
+       miptex32_t              *qtex32;
+       float                   scale_x, scale_y;
+       int                             mip_scale;
+       // detail texturing
+       char                    dt_name[128];
+       float                   dt_scale_x, dt_scale_y;
+       float                   dt_u, dt_v;
+       float                   dt_alpha;
+       int                             dt_src_blend_mode, dt_dst_blend_mode;
+       int                             flags2;
+
+
+       GetScriptToken (false);
+       strcpy (lumpname, token);
+       
+       GetScriptToken (false);
+       xl = atoi (token);
+       GetScriptToken (false);
+       yl = atoi (token);
+       GetScriptToken (false);
+       w = atoi (token);
+       GetScriptToken (false);
+       h = atoi (token);
+
+       total_x += w;
+       total_y += h;
+       total_textures++;
+
+       if ( (w & 15) || (h & 15) )
+               Error ("line %i: miptex sizes must be multiples of 16", scriptline);
+
+       flags = 0;
+       flags2 = 0;
+       contents = 0;
+       value = 0;
+       mip_scale = 0;
+
+       altname[0] = animname[0] = damagename[0] = 0;
+
+       scale_x = scale_y = 0.5;
+
+       // detail texturing
+       dt_name[0] = 0;
+       dt_scale_x = dt_scale_y = 0.0;
+       dt_u = dt_v = 0.0;
+       dt_alpha = 0.0;
+       dt_src_blend_mode = dt_dst_blend_mode = 0;
+
+       // get optional flags and values
+       while (ScriptTokenAvailable ())
+       {
+               GetScriptToken (false);
+       
+               for (mp=mipparms ; mp->name ; mp++)
+               {
+                       if (!strcmp(mp->name, token))
+                       {
+                               switch (mp->type)
+                               {
+                                       case pt_animvalue:
+                                               GetScriptToken (false); // specify the next animation frame
+                                               strcpy (animname, token);
+                                               break;
+                                       case pt_altnamevalue:
+                                               GetScriptToken (false); // specify the alternate texture
+                                               strcpy (altname, token);
+                                               break;
+                                       case pt_damagenamevalue:
+                                               GetScriptToken (false); // specify the damage texture
+                                               strcpy (damagename, token);
+                                               break;
+                                       case pt_flags:
+                                               flags |= mp->flags;
+                                               break;
+                                       case pt_contents:
+                                               contents |= mp->flags;
+                                               break;
+                                       case pt_flagvalue:
+                                               flags |= mp->flags;
+                                               GetScriptToken (false); // specify the light value
+                                               value = atoi(token);
+                                               break;
+                                       case pt_materialvalue:
+                                               GetScriptToken(false);
+                                               for (mat=materialtypes ; mat->name ; mat++)
+                                               {
+                                                       if (!strcmp(mat->name, token))
+                                                       {
+                                                               // assumes SURF_MATERIAL is in top 8 bits
+                                                               flags = (flags & 0x0FFFFFF) | (mat->value << 24);
+                                                               break;
+                                                       }
+                                               }
+                                               break;
+                                       case pt_scale:
+                                               GetScriptToken (false); // specify the x scale
+                                               scale_x = atof(token);
+                                               GetScriptToken (false); // specify the y scale
+                                               scale_y = atof(token);
+                                               break;
+
+                                       case pt_mip:
+                                               mip_scale = 1;
+                                               break;
+
+                                       case pt_detailer:
+                                               flags2 |= MIP32_DETAILER_FLAG2;
+                                               break;
+
+                                       case pt_nomip:
+                                               flags2 |= MIP32_NOMIP_FLAG2;
+                                               break;
+
+                                       case pt_detail:
+                                               GetScriptToken(false);
+                                               strcpy(dt_name, token);
+                                               GetScriptToken(false);
+                                               dt_scale_x = atof(token);
+                                               GetScriptToken(false);
+                                               dt_scale_y = atof(token);
+                                               GetScriptToken(false);
+                                               dt_u = atof(token);
+                                               GetScriptToken(false);
+                                               dt_v = atof(token);
+                                               GetScriptToken(false);
+                                               dt_alpha = atof(token);
+                                               GetScriptToken(false);
+                                               for (mp=mipparms ; mp->name ; mp++)
+                                               {
+                                                       if (!strcmp(mp->name, token))
+                                                       {
+                                                               if (mp->type == pt_gl)
+                                                               {
+                                                                       dt_src_blend_mode = mp->flags;
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                               if (!mp->name)
+                                               {
+                                                       Error ("line %i: invalid gl blend mode %s", scriptline, token);
+                                               }
+                                               GetScriptToken (false);
+                                               for (mp=mipparms ; mp->name ; mp++)
+                                               {
+                                                       if (!strcmp(mp->name, token))
+                                                       {
+                                                               if (mp->type == pt_gl)
+                                                               {
+                                                                       dt_dst_blend_mode = mp->flags;
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                               if (!mp->name)
+                                               {
+                                                       Error ("line %i: invalid gl blend mode %s", scriptline, token);
+                                               }
+                                               break;
+                               }
+                               break;
+                       }
+               }
+               if (!mp->name)
+                       Error ("line %i: unknown parm %s", scriptline, token);
+       }
+
+       if (g_release)
+               return; // textures are only released by $maps
+
+       xh = xl+w;
+       yh = yl+h;
+       if (xh*yh > MAX_IMAGE_SIZE*MAX_IMAGE_SIZE)
+       {
+               Error("line %i image %s: image is too big!", scriptline, lumpname);
+       }
+               
+       if (TrueColorImage)
+       {
+               if (xl >= longimagewidth || xh > longimagewidth ||
+                       yl >= longimageheight || yh > longimageheight)
+               {
+                       Error ("line %i image %s: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, lumpname, xl,yl,w,h,longimagewidth,longimageheight);
+               }
+
+               sourcel = longimage + (yl*longimagewidth) + xl;
+               destl = bufferl;
+               linedelta = (longimagewidth - w);
+
+               for (y=yl ; y<yh ; y++)
+               {
+                       for (x=xl ; x<xh ; x++)
+                       {
+                               *destl++ = *sourcel++;  // RGBA
+                       }
+                       sourcel += linedelta;
+               }
+
+               qtex32 = CreateMip32(bufferl, w, h, &size, true);
+
+               qtex32->flags |= LittleLong(flags);
+               qtex32->flags2 |= LittleLong(flags2);
+               qtex32->contents = LittleLong(contents);
+               qtex32->value = LittleLong(value);
+               qtex32->scale_x = scale_x;
+               qtex32->scale_y = scale_y;
+               qtex32->mip_scale = mip_scale;
+               sprintf (qtex32->name, "%s/%s", mip_prefix, lumpname);
+               if (animname[0])
+               {
+                       sprintf (qtex32->animname, "%s/%s", mip_prefix, animname);
+               }
+               if (altname[0])
+               {
+                       sprintf (qtex32->altname, "%s/%s", mip_prefix, altname);
+               }
+               if (damagename[0])
+               {
+                       sprintf (qtex32->damagename, "%s/%s", mip_prefix, damagename);
+               }
+               if (dt_name[0] & ((flags2 & MIP32_DETAILER_FLAG2) == 0)) 
+               {
+                       sprintf (qtex32->dt_name, "%s/%s", mip_prefix, dt_name);
+                       qtex32->dt_scale_x = dt_scale_x;
+                       qtex32->dt_scale_y = dt_scale_y;
+                       qtex32->dt_u = dt_u;
+                       qtex32->dt_v = dt_v;
+                       qtex32->dt_alpha = dt_alpha;
+                       qtex32->dt_src_blend_mode = dt_src_blend_mode;
+                       qtex32->dt_dst_blend_mode = dt_dst_blend_mode;
+               }
+               
+       //
+       // write it out
+       //
+               sprintf (filename, "%stextures/%s/%s.m32", g_outputDir, mip_prefix, lumpname);
+               if(qtex32->flags & (SURF_ALPHA_TEXTURE))
+                       printf ("writing %s with ALPHA\n", filename);
+               else
+                       printf ("writing %s\n", filename);
+               SaveFile (filename, (byte *)qtex32, size);
+
+               free (qtex32);
+       }
+       else
+       {
+               if (xl >= byteimagewidth || xh > byteimagewidth ||
+                       yl >= byteimageheight || yh > byteimageheight)
+               {
+                       Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,byteimagewidth,byteimageheight);
+               }
+
+               source = byteimage + yl*byteimagewidth + xl;
+               dest = buffer;
+               linedelta = byteimagewidth - w;
+
+               for (y=yl ; y<yh ; y++)
+               {
+                       for (x=xl ; x<xh ; x++)
+                       {
+                               *dest++ = *source++;
+                       }
+                       source += linedelta;
+               }
+
+               qtex = CreateMip(buffer, w, h, lbmpalette, &size, true);
+
+               qtex->flags = LittleLong(flags);
+               qtex->contents = LittleLong(contents);
+               qtex->value = LittleLong(value);
+               sprintf (qtex->name, "%s/%s", mip_prefix, lumpname);
+               if (animname[0])
+                       sprintf (qtex->animname, "%s/%s", mip_prefix, animname);
+               
+       //
+       // write it out
+       //
+               sprintf (filename, "%stextures/%s/%s.m8", g_outputDir, mip_prefix, lumpname);
+               printf ("writing %s\n", filename);
+               SaveFile (filename, (byte *)qtex, size);
+
+               free (qtex);
+       }
+}
+
+/*
+===============
+Cmd_Mippal
+===============
+*/
+void Cmd_Mippal (void)
+{
+       colormap_issued = true;
+       if (g_release)
+               return;
+
+       memcpy (colormap_palette, lbmpalette, 768);
+
+       BuildPalmap();
+}
+
+
+/*
+===============
+Cmd_Mipdir
+===============
+*/
+void Cmd_Mipdir (void)
+{
+       char    filename[1024];
+
+       GetScriptToken (false);
+       strcpy (mip_prefix, token);
+       // create the directory if needed
+       sprintf (filename, "%stextures", g_outputDir);
+       Q_mkdir (filename); 
+       sprintf (filename, "%stextures/%s", g_outputDir, mip_prefix);
+       Q_mkdir (filename); 
+}
+
+
+/*
+=============================================================================
+
+ENVIRONMENT MAP GRABBING
+
+Creates six pcx files from tga files without any palette edge seams
+also copies the tga files for GL rendering.
+=============================================================================
+*/
+
+// 3dstudio environment map suffixes
+char   *suf[6] = {"rt", "ft", "lf", "bk", "up", "dn"};
+
+/*
+=================
+Cmd_Environment
+=================
+*/
+void Cmd_Environment (void)
+{
+       char    name[1024];
+       int             i, x, y;
+       byte    image[256*256];
+       byte    *tga;
+
+       GetScriptToken (false);
+
+       if (g_release)
+       {
+               for (i=0 ; i<6 ; i++)
+               {
+                       sprintf (name, "env/%s%s.pcx", token, suf[i]);
+                       ReleaseFile (name);
+                       sprintf (name, "env/%s%s.tga", token, suf[i]);
+                       ReleaseFile (name);
+               }
+               return;
+       }
+       // get the palette
+       BuildPalmap ();
+
+       sprintf (name, "%senv/", gamedir);
+       CreatePath (name);
+
+       // convert the images
+       for (i=0 ; i<6 ; i++)
+       {
+               sprintf (name, "%senv/%s%s.tga", gamedir, token, suf[i]);
+               printf ("loading %s...\n", name);
+               LoadTGA (name, &tga, NULL, NULL);
+
+               for (y=0 ; y<256 ; y++)
+               {
+                       for (x=0 ; x<256 ; x++)
+                       {
+                               image[y*256+x] = FindColor (tga[(y*256+x)*4+0],tga[(y*256+x)*4+1],tga[(y*256+x)*4+2]);
+                       }
+               }
+               free (tga);
+               sprintf (name, "%senv/%s%s.pcx", gamedir, token, suf[i]);
+               if (FileTime (name) != -1)
+                       printf ("%s already exists, not overwriting.\n", name);
+               else
+                       WritePCXfile (name, image, 256, 256, colormap_palette);
+       }
+}
+