-/*\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);
+ }
+}
+