]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/qdata_heretic2/images.c
set eol-style
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / images.c
1 /*
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #include "qdata.h"
23
24 #ifdef _WIN32
25  #include <windows.h>
26 #endif
27
28 #include <GL/gl.h>
29
30 #if 1
31         extern char             *g_outputDir;
32 #endif // _QDATA
33
34 char            mip_prefix[1024];               // directory to dump the textures in
35
36 qboolean        colormap_issued;
37 byte            colormap_palette[768];
38
39 unsigned total_x = 0;
40 unsigned total_y = 0;
41 unsigned total_textures = 0;
42
43 #define MAX_IMAGE_SIZE 512
44
45 #if     0
46 /*
47 ==============
48 RemapZero
49
50 Replaces all 0 bytes in an image with the closest palette entry.
51 This is because NT won't let us change index 0, so any palette
52 animation leaves those pixels untouched.
53 ==============
54 */
55 void RemapZero (byte *pixels, byte *palette, int width, int height)
56 {
57         int             i, c;
58         int             alt_zero;
59         int             value, best;
60
61         alt_zero = 0;
62         best = 9999999;
63         for (i=1 ; i<255 ; i++)
64         {
65                 value = palette[i*3+0]+palette[i*3+1]+palette[i*3+2];
66                 if (value < best)
67                 {
68                         best = value;
69                         alt_zero = i;
70                 }
71         }
72
73         c = width*height;
74         for (i=0 ; i<c ; i++)
75                 if (pixels[i] == 0)
76                         pixels[i] = alt_zero;
77 }
78
79 #endif
80
81
82 // ********************************************************************
83 // **  Mip Map Pre-Processing Routines
84 // ********************************************************************
85
86 #define intensity_value 1
87
88 static unsigned image_pal[256];
89
90 #define MAX_LAST 25
91
92 long palette_r[256], palette_g[256], palette_b[256];
93 long last_r[MAX_LAST],last_g[MAX_LAST],last_b[MAX_LAST], last_i[MAX_LAST], last_place;
94
95 long cached;
96
97 void PrepareConvert(unsigned *palette)
98 {
99         int i;
100
101         for(i=0;i<256;i++)
102         {
103                 palette_r[i] = (palette[i] & 0x00ff0000) >> 16;
104                 palette_g[i] = (palette[i] & 0x0000ff00) >> 8;
105                 palette_b[i] = (palette[i] & 0x000000ff);
106         }
107
108         for(i=0;i<MAX_LAST;i++)
109                 last_r[i] = -1;
110
111         last_place = -1;
112 }
113
114 int ConvertTrueColorToPal(unsigned r, unsigned g, unsigned b)
115 {
116         int i;
117         long min_dist;
118         int min_index;
119         long dist;
120         long dr, dg, db, biggest_delta;
121
122         for(i=0;i<MAX_LAST;i++)
123                 if (r == last_r[i] && g == last_g[i] && b == last_b[i])
124                 {
125                         cached++;
126                         return last_i[i];
127                 }
128
129         min_dist = 256 * 256 + 256 * 256 + 256 * 256;
130         biggest_delta = 256*256;
131         min_index = 0;
132
133         for (i=0;i<256;i++)
134         {
135                 dr = abs(palette_r[i] - r);
136                 if (dr > biggest_delta)
137                         continue;
138                 dg = abs(palette_g[i] - g);
139                 if (dg > biggest_delta)
140                         continue;
141                 db = abs(palette_b[i] - b);
142                 if (db > biggest_delta)
143                         continue;
144
145                 dist = dr * dr + dg * dg + db * db;
146                 if (dist < min_dist)
147                 {
148                         min_dist = dist;
149                         min_index = i;
150                         if (min_dist == 0) break;
151
152                         dist = dr;
153                         if (dg > dist) dist = dg;
154                         if (db > dist) dist = db;
155                         if (dist < biggest_delta)
156                                 biggest_delta = dist;
157                 }
158         }
159
160         last_place++;
161         if (last_place >= MAX_LAST)
162                 last_place = 0;
163
164         last_r[last_place] = r;
165         last_g[last_place] = g;
166         last_b[last_place] = b;
167         last_i[last_place] = min_index;
168
169         return min_index;
170 }
171
172
173 void GL_ResampleTexture8P (byte *in, int inwidth, int inheight, byte *out,  
174                                                    int outwidth, int outheight, palette_t *palette)
175 {
176         int             i, j;
177         byte    *inrow, *inrow2;
178         unsigned        frac, fracstep;
179         unsigned        p1[1024], p2[1024], *p1p, *p2p;
180         palette_t       *c1,*c2,*c3,*c4;
181         unsigned        r,g,b;
182         
183         fracstep = inwidth*0x10000/outwidth;
184
185         frac = fracstep>>2;
186         for (i=0 ; i<outwidth ; i++)
187         {
188                 p1[i] = frac>>16;
189                 frac += fracstep;
190         }
191         frac = 3*(fracstep>>2);
192         for (i=0 ; i<outwidth ; i++)
193         {
194                 p2[i] = frac>>16;
195                 frac += fracstep;
196         }
197
198         cached = 0;
199         
200         for (i=0 ; i<outheight ; i++)//, out += outwidth)
201         {
202                 inrow = in + inwidth*(int)((i+0.25)*inheight/outheight);
203                 inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight);
204
205                 p1p = p1;
206                 p2p = p2;
207                 for (j=0 ; j<outwidth ; j++)
208                 {
209                         c1 = &palette[*((byte *)inrow + (*p1p))];
210                         c2 = &palette[*((byte *)inrow + (*p2p))];
211                         c3 = &palette[*((byte *)inrow2 + (*p1p++))];
212                         c4 = &palette[*((byte *)inrow2 + (*p2p++))];
213
214                         r = ((unsigned)c1->r + (unsigned)c2->r + (unsigned)c3->r + (unsigned)c4->r)>>2;
215                         g = ((unsigned)c1->g + (unsigned)c2->g + (unsigned)c3->g + (unsigned)c4->g)>>2;
216                         b = ((unsigned)c1->b + (unsigned)c2->b + (unsigned)c3->b + (unsigned)c4->b)>>2;
217
218                         *out++ = ConvertTrueColorToPal(r,g,b);
219                 }
220         }
221 }
222
223 void GL_MipMap8P(byte *out, byte *in, int width, int height, palette_t *palette)
224 {
225         int                     i, j;
226         palette_t       *c1,*c2,*c3,*c4;
227         unsigned        r,g,b;
228
229         cached = 0;
230         memset(out, 0, 256 * 256);
231         width <<= 1;
232         height <<= 1;
233
234         for (i = 0; i < height; i += 2, in += width)
235         {
236                 for (j = 0; j < width; j += 2)
237                 {
238                         c1 = &palette[in[0]];
239                         c3 = &palette[in[width]];
240                         in++;
241                         c2 = &palette[in[0]];
242                         c4 = &palette[in[width]];
243                         in++;
244
245                         r = ((unsigned)c1->r + (unsigned)c2->r + (unsigned)c3->r + (unsigned)c4->r) >> 2;
246                         g = ((unsigned)c1->g + (unsigned)c2->g + (unsigned)c3->g + (unsigned)c4->g) >> 2;
247                         b = ((unsigned)c1->b + (unsigned)c2->b + (unsigned)c3->b + (unsigned)c4->b) >> 2;
248
249                         *out++ = ConvertTrueColorToPal(r, g, b);
250                 }
251         }
252 }
253
254
255 miptex_t *CreateMip(byte *data, unsigned width, unsigned height, byte *palette, int *FinalSize, qboolean mip)
256 {
257         int                     scaled_width, scaled_height;
258         int                     i,j,r,g,b;
259         byte            intensitytable[256];
260         byte            scaled[256*256];
261         byte            out[256*256];
262         int                     miplevel;
263         miptex_t        *mp;
264         byte            *pos;
265         int                     size;
266
267         for (i=0 ; i<256 ; i++)
268         {
269                 j = i * intensity_value;
270                 if (j > 255)
271                         j = 255;
272                 intensitytable[i] = j;
273         }
274
275         for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
276                 ;
277         if (1 && scaled_width > width && 1)
278                 scaled_width >>= 1;
279         for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
280                 ;
281         if (1 && scaled_height > height && 1)
282                 scaled_height >>= 1;
283
284         // don't ever bother with >256 textures
285         if (scaled_width > 256)
286                 scaled_width = 256;
287         if (scaled_height > 256)
288                 scaled_height = 256;
289
290         if (scaled_width < 1)
291                 scaled_width = 1;
292         if (scaled_height < 1)
293                 scaled_height = 1;
294
295         size = sizeof(*mp) + (scaled_width*scaled_height*3);
296         mp = (miptex_t *)SafeMalloc(size, "CreateMip");
297         memset(mp,0,size);
298
299         mp->version = MIP_VERSION;
300
301         for(i=j=0;i<256;i++,j+=3)
302         {
303                 mp->palette[i].r = r = intensitytable[palette[j]];
304                 mp->palette[i].g = g = intensitytable[palette[j+1]];
305                 mp->palette[i].b = b = intensitytable[palette[j+2]];
306                 image_pal[i] = 0xff000000 | (r<<16) | (g<<8) | (b);
307         }
308
309         PrepareConvert(image_pal);
310
311         if (scaled_width == width && scaled_height == height)
312         {
313                 memcpy (scaled, data, width*height);
314         }
315         else
316                 GL_ResampleTexture8P (data, width, height, scaled, scaled_width, scaled_height, mp->palette);
317
318         pos = (byte *)(mp + 1);
319         miplevel = 0;
320
321         while ((scaled_width >= 1 || scaled_height >= 1) && (miplevel <= MIPLEVELS-1) && (!miplevel || mip))
322         {
323                 if (scaled_width < 1)
324                         scaled_width = 1;
325                 if (scaled_height < 1)
326                         scaled_height = 1;
327
328                 if(miplevel > 0)
329                         GL_MipMap8P(out, (byte *)scaled, scaled_width, scaled_height, mp->palette);
330                 else
331                         memcpy(out, scaled, 256 * 256);
332
333                 mp->width[miplevel] = scaled_width;
334                 mp->height[miplevel] = scaled_height;
335                 mp->offsets[miplevel] = pos - ((byte *)(mp));
336                 memcpy(pos, out, scaled_width * scaled_height);
337                 memcpy(scaled, out, 256 * 256);
338                 pos += scaled_width * scaled_height;
339
340                 scaled_width >>= 1;
341                 scaled_height >>= 1;
342
343                 miplevel++;
344         }
345
346         *FinalSize = pos - ((byte *)(mp));
347
348         return mp;
349 }
350
351
352 void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out,  int outwidth, int outheight)
353 {
354         int             i, j;
355         unsigned        *inrow, *inrow2;
356         unsigned        frac, fracstep;
357         unsigned        p1[1024], p2[1024];
358         byte            *pix1, *pix2, *pix3, *pix4;
359
360         fracstep = inwidth*0x10000/outwidth;
361
362         frac = fracstep>>2;
363         for (i=0 ; i<outwidth ; i++)
364         {
365                 p1[i] = 4*(frac>>16);
366                 frac += fracstep;
367         }
368         frac = 3*(fracstep>>2);
369         for (i=0 ; i<outwidth ; i++)
370         {
371                 p2[i] = 4*(frac>>16);
372                 frac += fracstep;
373         }
374
375         for (i=0 ; i<outheight ; i++, out += outwidth)
376         {
377                 inrow = in + inwidth*(int)((i+0.25)*inheight/outheight);
378                 inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight);
379                 frac = fracstep >> 1;
380                 for (j=0 ; j<outwidth ; j++)
381                 {
382                         pix1 = (byte *)inrow + p1[j];
383                         pix2 = (byte *)inrow + p2[j];
384                         pix3 = (byte *)inrow2 + p1[j];
385                         pix4 = (byte *)inrow2 + p2[j];
386                         ((byte *)(out+j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>2;
387                         ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2;
388                         ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2;
389                         ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2;
390                 }
391         }
392 }
393
394 void GL_MipMap (byte *out, byte *in, int width, int height)
395 {
396         int             i, j;
397
398         width <<=3;
399         height <<= 1;
400         for (i=0 ; i<height ; i++, in+=width)
401         {
402                 for (j=0 ; j<width ; j+=8, out+=4, in+=8)
403                 {
404                         out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>2;
405                         out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2;
406                         out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2;
407                         out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2;
408                 }
409         }
410 }
411
412 miptex32_t *CreateMip32(unsigned *data, unsigned width, unsigned height, int *FinalSize, qboolean mip)
413 {
414         int                             scaled_width, scaled_height;
415         unsigned                scaled[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE];
416         unsigned                out[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE];
417         int                             miplevel;
418         miptex32_t              *mp;
419         byte                    *pos;
420         int                             size;
421         paletteRGBA_t   *test;
422
423         for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
424                 ;
425         if (1 && scaled_width > width && 1)
426                 scaled_width >>= 1;
427         for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
428                 ;
429         if (1 && scaled_height > height && 1)
430                 scaled_height >>= 1;
431
432         // don't ever bother with >256 textures
433         if (scaled_width > MAX_IMAGE_SIZE)
434                 scaled_width = MAX_IMAGE_SIZE;
435         if (scaled_height > MAX_IMAGE_SIZE)
436                 scaled_height = MAX_IMAGE_SIZE;
437
438         if (scaled_width < 1)
439                 scaled_width = 1;
440         if (scaled_height < 1)
441                 scaled_height = 1;
442
443         size = sizeof(*mp) + (scaled_width*scaled_height*3*4);
444         mp = (miptex32_t *)SafeMalloc(size, "CreateMip");
445         memset(mp,0,size);
446
447         mp->version = MIP32_VERSION;
448
449         size = width*height;
450         test = (paletteRGBA_t *)data;
451         while(size)
452         {
453                 if (test->a != 255)
454                 {
455                         mp->flags |= LittleLong(SURF_ALPHA_TEXTURE);
456                         break;
457                 }
458
459                 size--;
460                 test++;
461         }
462
463         if (scaled_width == width && scaled_height == height)
464         {
465                 memcpy (scaled, data, width*height*4);
466         }
467         else
468                 GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);
469
470         pos = (byte *)(mp + 1);
471         miplevel = 0;
472
473         while ((scaled_width >= 1 || scaled_height >= 1) && (miplevel <= MIPLEVELS-1) && (!miplevel || mip))
474         {
475                 if (scaled_width < 1)
476                         scaled_width = 1;
477                 if (scaled_height < 1)
478                         scaled_height = 1;
479
480                 if (miplevel > 0)
481                 {
482                         GL_MipMap((byte *)out, (byte *)scaled, scaled_width, scaled_height);
483                 }
484                 else
485                 {
486                         memcpy(out, scaled, MAX_IMAGE_SIZE * MAX_IMAGE_SIZE * 4);
487                 }
488
489                 mp->width[miplevel] = scaled_width;
490                 mp->height[miplevel] = scaled_height;
491                 mp->offsets[miplevel] = pos - ((byte *)(mp));
492                 memcpy(pos, out, scaled_width * scaled_height * 4);
493                 memcpy(scaled, out, MAX_IMAGE_SIZE * MAX_IMAGE_SIZE * 4);
494                 pos += scaled_width * scaled_height * 4;
495
496                 scaled_width >>= 1;
497                 scaled_height >>= 1;
498
499                 miplevel++;
500         }
501
502         *FinalSize = pos - ((byte *)(mp));
503
504         return mp;
505 }
506
507 /*
508 ==============
509 Cmd_Grab
510
511 $grab filename x y width height
512 ==============
513 */
514 void Cmd_Grab (void)
515 {
516         int             xl,yl,w,h,y;
517         byte                    *cropped;
518         char                    savename[1024];
519         char                    dest[1024];
520
521         GetScriptToken (false);
522
523         if (token[0] == '/' || token[0] == '\\')
524                 sprintf (savename, "%s%s.pcx", gamedir, token+1);
525         else
526                 sprintf (savename, "%spics/%s.pcx", gamedir, token);
527
528         if (g_release)
529         {
530                 if (token[0] == '/' || token[0] == '\\')
531                         sprintf (dest, "%s.pcx", token+1);
532                 else
533                         sprintf (dest, "pics/%s.pcx", token);
534
535                 ReleaseFile (dest);
536                 return;
537         }
538
539         GetScriptToken (false);
540         xl = atoi (token);
541         GetScriptToken (false);
542         yl = atoi (token);
543         GetScriptToken (false);
544         w = atoi (token);
545         GetScriptToken (false);
546         h = atoi (token);
547
548         if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight)
549                 Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h);
550
551         // crop it to the proper size
552         cropped = (byte *) SafeMalloc (w*h, "Cmd_Grab");
553         for (y=0 ; y<h ; y++)
554         {
555                 memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);
556         }
557
558         // save off the new image
559         printf ("saving %s\n", savename);
560         CreatePath (savename);
561         WritePCXfile (savename, cropped, w,     h, lbmpalette);
562
563         free (cropped);
564 }
565
566 /*
567 ==============
568 Cmd_Raw
569
570 $grab filename x y width height
571 ==============
572 */
573 void Cmd_Raw (void)
574 {
575         int             xl,yl,w,h,y;
576         byte                    *cropped;
577         char                    savename[1024];
578         char                    dest[1024];
579
580         GetScriptToken (false);
581
582         sprintf (savename, "%s%s.lmp", gamedir, token);
583
584         if (g_release)
585         {
586                 sprintf (dest, "%s.lmp", token);
587                 ReleaseFile (dest);
588                 return;
589         }
590
591         GetScriptToken (false);
592         xl = atoi (token);
593         GetScriptToken (false);
594         yl = atoi (token);
595         GetScriptToken (false);
596         w = atoi (token);
597         GetScriptToken (false);
598         h = atoi (token);
599
600         if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight)
601                 Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h);
602
603         // crop it to the proper size
604         cropped = (byte *) SafeMalloc (w*h, "Cmd_Raw");
605         for (y=0 ; y<h ; y++)
606         {
607                 memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);
608         }
609
610         // save off the new image
611         printf ("saving %s\n", savename);
612         CreatePath (savename);
613
614         SaveFile (savename, cropped, w*h);
615
616         free (cropped);
617 }
618
619 /*
620 =============================================================================
621
622 COLORMAP GRABBING
623
624 =============================================================================
625 */
626
627 /*
628 ===============
629 BestColor
630 ===============
631 */
632 byte BestColor (int r, int g, int b, int start, int stop)
633 {
634         int     i;
635         int     dr, dg, db;
636         int     bestdistortion, distortion;
637         int     bestcolor;
638         byte    *pal;
639
640 //
641 // let any color go to 0 as a last resort
642 //
643         bestdistortion = 256*256*4;
644         bestcolor = 0;
645
646         pal = colormap_palette + start*3;
647         for (i=start ; i<= stop ; i++)
648         {
649                 dr = r - (int)pal[0];
650                 dg = g - (int)pal[1];
651                 db = b - (int)pal[2];
652                 pal += 3;
653                 distortion = dr*dr + dg*dg + db*db;
654                 if (distortion < bestdistortion)
655                 {
656                         if (!distortion)
657                                 return i;               // perfect match
658
659                         bestdistortion = distortion;
660                         bestcolor = i;
661                 }
662         }
663
664         return bestcolor;
665 }
666
667
668 /*
669 ==============
670 Cmd_Colormap
671
672 $colormap filename
673
674   the brightes colormap is first in the table (FIXME: reverse this now?)
675
676   64 rows of 256 : lightmaps
677   256 rows of 256 : translucency table
678 ==============
679 */
680 void Cmd_Colormap (void)
681 {
682         int             levels, brights;
683         int             l, c;
684         float   frac, red, green, blue;
685         float   range;
686         byte    *cropped, *lump_p;
687         char    savename[1024];
688         char    dest[1024];
689
690         colormap_issued = true;
691         if (!g_release)
692                 memcpy (colormap_palette, lbmpalette, 768);
693
694         if (!ScriptTokenAvailable ())
695         {       // just setting colormap_issued
696                 return;
697         }
698
699         GetScriptToken (false);
700         sprintf (savename, "%spics/%s.pcx", gamedir, token);
701
702         if (g_release)
703         {
704                 sprintf (dest, "pics/%s.pcx", token);
705                 ReleaseFile (dest);
706                 return;
707         }
708
709         range = 2;
710         levels = 64;
711         brights = 1;    // ignore 255 (transparent)
712
713         cropped = (byte *) SafeMalloc((levels+256)*256, "Cmd_ColorMap");
714         lump_p = cropped;
715
716 // shaded levels
717         for (l=0;l<levels;l++)
718         {
719                 frac = range - range*(float)l/(levels-1);
720                 for (c=0 ; c<256-brights ; c++)
721                 {
722                         red = lbmpalette[c*3];
723                         green = lbmpalette[c*3+1];
724                         blue = lbmpalette[c*3+2];
725
726                         red = (int)(red*frac+0.5);
727                         green = (int)(green*frac+0.5);
728                         blue = (int)(blue*frac+0.5);
729                         
730 //
731 // note: 254 instead of 255 because 255 is the transparent color, and we
732 // don't want anything remapping to that
733 // don't use color 0, because NT can't remap that (or 255)
734 //
735                         *lump_p++ = BestColor(red,green,blue, 1, 254);
736                 }
737
738                 // fullbrights allways stay the same
739                 for ( ; c<256 ; c++)
740                         *lump_p++ = c;
741         }
742         
743 // 66% transparancy table
744         for (l=0;l<255;l++)
745         {
746                 for (c=0 ; c<255 ; c++)
747                 {
748                         red = lbmpalette[c*3]*0.33 + lbmpalette[l*3]*0.66;
749                         green = lbmpalette[c*3+1]*0.33 + lbmpalette[l*3+1]*0.66;
750                         blue = lbmpalette[c*3+2]*0.33 + lbmpalette[l*3+2]*0.66;
751
752                         *lump_p++ = BestColor(red,green,blue, 1, 254);
753                 }
754                 *lump_p++ = 255;
755         }
756         for (c=0 ; c<256 ; c++)
757                 *lump_p++ = 255;
758         
759         // save off the new image
760         printf ("saving %s\n", savename);
761         CreatePath (savename);
762         WritePCXfile (savename, cropped, 256, levels+256, lbmpalette);
763
764         free (cropped);
765 }
766
767 /*
768 =============================================================================
769
770 MIPTEX GRABBING
771
772 =============================================================================
773 */
774
775 byte    pixdata[256];
776
777 int             d_red, d_green, d_blue;
778
779 byte    palmap[32][32][32];
780 qboolean        palmap_built;
781
782 /*
783 =============
784 FindColor
785 =============
786 */
787 int FindColor (int r, int g, int b)
788 {
789         int             bestcolor;
790
791         if (r > 255)
792                 r = 255;
793         if (r < 0)
794                 r = 0;
795         if (g > 255)
796                 g = 255;
797         if (g < 0)
798                 g = 0;
799         if (b > 255)
800                 b = 255;
801         if (b < 0)
802                 b = 0;
803 #ifndef TABLECOLORS
804         bestcolor = BestColor (r, g, b, 0, 254);
805 #else
806         bestcolor = palmap[r>>3][g>>3][b>>3];
807 #endif
808
809         return bestcolor;
810 }
811
812
813 void BuildPalmap (void)
814 {
815 #ifdef TABLECOLORS
816         int             r, g, b;
817         int             bestcolor;
818
819         if (palmap_built)
820                 return;
821         palmap_built = true;
822
823         for (r=4 ; r<256 ; r+=8)
824         {
825                 for (g=4 ; g<256 ; g+=8)
826                 {
827                         for (b=4 ; b<256 ; b+=8)
828                         {
829                                 bestcolor = BestColor (r, g, b, 1, 254);
830                                 palmap[r>>3][g>>3][b>>3] = bestcolor;
831                         }
832                 }
833         }
834 #endif
835
836         if (!colormap_issued)
837                 Error ("You must issue a $colormap command first");
838
839 }
840
841 /*
842 =============
843 AveragePixels
844 =============
845 */
846 byte AveragePixels (int count)
847 {
848         int             r,g,b;
849         int             i;
850         int             vis;
851         int             pix;
852         int             bestcolor;
853         byte    *pal;
854         int             fullbright;
855         
856         vis = 0;
857         r = g = b = 0;
858         fullbright = 0;
859         for (i=0 ; i<count ; i++)
860         {
861                 pix = pixdata[i];
862                 
863                 r += lbmpalette[pix*3];
864                 g += lbmpalette[pix*3+1];
865                 b += lbmpalette[pix*3+2];
866                 vis++;
867         }
868                 
869         r /= vis;
870         g /= vis;
871         b /= vis;
872
873         // error diffusion
874         r += d_red;
875         g += d_green;
876         b += d_blue;
877         
878 //
879 // find the best color
880 //
881         bestcolor = FindColor (r, g, b);
882
883         // error diffusion
884         pal = colormap_palette + bestcolor*3;
885         d_red = r - (int)pal[0];
886         d_green = g - (int)pal[1];
887         d_blue = b - (int)pal[2];
888
889         return bestcolor;
890 }
891
892
893 typedef enum
894 {
895         pt_contents,
896         pt_flags,
897         pt_animvalue,
898         pt_altnamevalue,
899         pt_damagenamevalue,
900         pt_flagvalue,
901         pt_materialvalue,
902         pt_scale,
903         pt_mip,
904         pt_detail,
905         pt_gl,
906         pt_nomip,
907         pt_detailer,
908 } parmtype_t;
909
910 typedef struct
911 {
912         char    *name;
913         int             flags;
914         parmtype_t      type;
915 } mipparm_t;
916
917 mipparm_t       mipparms[] =
918 {
919         // utility content attributes
920         {"pushpull",CONTENTS_PUSHPULL, pt_contents},
921         {"water",       CONTENTS_WATER, pt_contents},
922         {"slime",       CONTENTS_SLIME, pt_contents},           // mildly damaging
923         {"lava",        CONTENTS_LAVA, pt_contents},            // very damaging
924         {"window",      CONTENTS_WINDOW, pt_contents},  // solid, but doesn't eat internal textures
925         {"mist",        CONTENTS_MIST, pt_contents},    // non-solid window
926         {"origin",      CONTENTS_ORIGIN, pt_contents},  // center of rotating brushes
927         {"playerclip",  CONTENTS_PLAYERCLIP, pt_contents},
928         {"monsterclip", CONTENTS_MONSTERCLIP, pt_contents},
929
930         // utility surface attributes
931         {"hint",        SURF_HINT, pt_flags},
932         {"skip",        SURF_SKIP, pt_flags},
933         {"light",       SURF_LIGHT, pt_flagvalue},              // value is the light quantity
934
935         {"animspeed",SURF_ANIMSPEED, pt_flagvalue},             // value will hold the anim speed in fps
936
937         // texture chaining
938         {"anim",        0,                      pt_animvalue},          // animname is the next animation
939         {"alt",         0,                      pt_altnamevalue},       // altname is the alternate texture
940         {"damage",      0,                      pt_damagenamevalue},    // damagename is the damage texture
941         {"scale",       0,                      pt_scale},              // next two values are for scale
942         {"mip",         0,                      pt_mip},                
943         {"detail",      0,                      pt_detail},             
944
945         {"GL_ZERO",                                     GL_ZERO,                                pt_gl},
946         {"GL_ONE",                                      GL_ONE,                                 pt_gl},
947         {"GL_SRC_COLOR",                        GL_SRC_COLOR,                   pt_gl},
948         {"GL_ONE_MINUS_SRC_COLOR",      GL_ONE_MINUS_SRC_COLOR, pt_gl},
949         {"GL_DST_COLOR",                        GL_DST_COLOR,                   pt_gl},
950         {"GL_ONE_MINUS_DST_COLOR",      GL_ONE_MINUS_DST_COLOR, pt_gl},
951         {"GL_SRC_ALPHA",                        GL_SRC_ALPHA,                   pt_gl},
952         {"GL_ONE_MINUS_SRC_ALPHA",      GL_ONE_MINUS_SRC_ALPHA, pt_gl},
953         {"GL_DST_ALPHA",                        GL_DST_ALPHA,                   pt_gl},
954         {"GL_ONE_MINUS_DST_ALPHA",      GL_ONE_MINUS_DST_ALPHA, pt_gl},
955         {"GL_SRC_ALPHA_SATURATE",       GL_SRC_ALPHA_SATURATE,  pt_gl},
956
957         // server attributes
958         {"slick",       SURF_SLICK, pt_flags},
959
960         // drawing attributes
961         {"sky",         SURF_SKY, pt_flags},
962         {"warping",     SURF_WARP, pt_flags},           // only valid with 64x64 textures
963         {"trans33",     SURF_TRANS33, pt_flags},        // translucent should allso set fullbright
964         {"trans66",     SURF_TRANS66, pt_flags},
965         {"flowing",     SURF_FLOWING, pt_flags},        // flow direction towards angle 0
966         {"nodraw",      SURF_NODRAW, pt_flags}, // for clip textures and trigger textures
967         {"alpha",       SURF_ALPHA_TEXTURE, pt_flags},
968         {"undulate",    SURF_UNDULATE, pt_flags},               // rock surface up and down...
969         {"skyreflect",  SURF_SKYREFLECT, pt_flags},             // liquid will somewhat reflect the sky - not quite finished....
970
971         {"material", SURF_MATERIAL, pt_materialvalue},
972         {"metal",       SURF_TYPE_METAL, pt_flags},
973         {"stone",       SURF_TYPE_STONE, pt_flags},
974         {"wood",        SURF_TYPE_WOOD, pt_flags},
975
976         {"m_nomip", 0, pt_nomip},
977         {"m_detail", 0, pt_detailer},
978
979         {NULL, 0, pt_contents}
980 };
981
982 /*
983 ==============
984 Cmd_Mip
985
986 $mip filename x y width height <OPTIONS>
987 must be multiples of sixteen
988 SURF_WINDOW
989 ==============
990 */
991
992 void Cmd_Mip (void)
993 {
994         int             xl,yl,xh,yh,w,h;
995         byte            *dest, *source;
996         int                             flags, value, contents;
997         mipparm_t               *mp;
998         char                    lumpname[128];
999         char                    altname[128];
1000         char                    animname[128];
1001         char                    damagename[128];
1002         byte                    buffer[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE];
1003         unsigned                bufferl[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE];
1004         materialtype_t  *mat;
1005         char                    filename[1024];
1006         unsigned        *destl, *sourcel;
1007         int             linedelta, x, y;
1008         int                             size;
1009         miptex_t                *qtex;
1010         miptex32_t              *qtex32;
1011         float                   scale_x, scale_y;
1012         int                             mip_scale;
1013         // detail texturing
1014         char                    dt_name[128];
1015         float                   dt_scale_x, dt_scale_y;
1016         float                   dt_u, dt_v;
1017         float                   dt_alpha;
1018         int                             dt_src_blend_mode, dt_dst_blend_mode;
1019         int                             flags2;
1020
1021
1022         GetScriptToken (false);
1023         strcpy (lumpname, token);
1024         
1025         GetScriptToken (false);
1026         xl = atoi (token);
1027         GetScriptToken (false);
1028         yl = atoi (token);
1029         GetScriptToken (false);
1030         w = atoi (token);
1031         GetScriptToken (false);
1032         h = atoi (token);
1033
1034         total_x += w;
1035         total_y += h;
1036         total_textures++;
1037
1038         if ( (w & 15) || (h & 15) )
1039                 Error ("line %i: miptex sizes must be multiples of 16", scriptline);
1040
1041         flags = 0;
1042         flags2 = 0;
1043         contents = 0;
1044         value = 0;
1045         mip_scale = 0;
1046
1047         altname[0] = animname[0] = damagename[0] = 0;
1048
1049         scale_x = scale_y = 0.5;
1050
1051         // detail texturing
1052         dt_name[0] = 0;
1053         dt_scale_x = dt_scale_y = 0.0;
1054         dt_u = dt_v = 0.0;
1055         dt_alpha = 0.0;
1056         dt_src_blend_mode = dt_dst_blend_mode = 0;
1057
1058         // get optional flags and values
1059         while (ScriptTokenAvailable ())
1060         {
1061                 GetScriptToken (false);
1062         
1063                 for (mp=mipparms ; mp->name ; mp++)
1064                 {
1065                         if (!strcmp(mp->name, token))
1066                         {
1067                                 switch (mp->type)
1068                                 {
1069                                         case pt_animvalue:
1070                                                 GetScriptToken (false); // specify the next animation frame
1071                                                 strcpy (animname, token);
1072                                                 break;
1073                                         case pt_altnamevalue:
1074                                                 GetScriptToken (false); // specify the alternate texture
1075                                                 strcpy (altname, token);
1076                                                 break;
1077                                         case pt_damagenamevalue:
1078                                                 GetScriptToken (false); // specify the damage texture
1079                                                 strcpy (damagename, token);
1080                                                 break;
1081                                         case pt_flags:
1082                                                 flags |= mp->flags;
1083                                                 break;
1084                                         case pt_contents:
1085                                                 contents |= mp->flags;
1086                                                 break;
1087                                         case pt_flagvalue:
1088                                                 flags |= mp->flags;
1089                                                 GetScriptToken (false); // specify the light value
1090                                                 value = atoi(token);
1091                                                 break;
1092                                         case pt_materialvalue:
1093                                                 GetScriptToken(false);
1094                                                 for (mat=materialtypes ; mat->name ; mat++)
1095                                                 {
1096                                                         if (!strcmp(mat->name, token))
1097                                                         {
1098                                                                 // assumes SURF_MATERIAL is in top 8 bits
1099                                                                 flags = (flags & 0x0FFFFFF) | (mat->value << 24);
1100                                                                 break;
1101                                                         }
1102                                                 }
1103                                                 break;
1104                                         case pt_scale:
1105                                                 GetScriptToken (false); // specify the x scale
1106                                                 scale_x = atof(token);
1107                                                 GetScriptToken (false); // specify the y scale
1108                                                 scale_y = atof(token);
1109                                                 break;
1110
1111                                         case pt_mip:
1112                                                 mip_scale = 1;
1113                                                 break;
1114
1115                                         case pt_detailer:
1116                                                 flags2 |= MIP32_DETAILER_FLAG2;
1117                                                 break;
1118
1119                                         case pt_nomip:
1120                                                 flags2 |= MIP32_NOMIP_FLAG2;
1121                                                 break;
1122
1123                                         case pt_detail:
1124                                                 GetScriptToken(false);
1125                                                 strcpy(dt_name, token);
1126                                                 GetScriptToken(false);
1127                                                 dt_scale_x = atof(token);
1128                                                 GetScriptToken(false);
1129                                                 dt_scale_y = atof(token);
1130                                                 GetScriptToken(false);
1131                                                 dt_u = atof(token);
1132                                                 GetScriptToken(false);
1133                                                 dt_v = atof(token);
1134                                                 GetScriptToken(false);
1135                                                 dt_alpha = atof(token);
1136                                                 GetScriptToken(false);
1137                                                 for (mp=mipparms ; mp->name ; mp++)
1138                                                 {
1139                                                         if (!strcmp(mp->name, token))
1140                                                         {
1141                                                                 if (mp->type == pt_gl)
1142                                                                 {
1143                                                                         dt_src_blend_mode = mp->flags;
1144                                                                         break;
1145                                                                 }
1146                                                         }
1147                                                 }
1148                                                 if (!mp->name)
1149                                                 {
1150                                                         Error ("line %i: invalid gl blend mode %s", scriptline, token);
1151                                                 }
1152                                                 GetScriptToken (false);
1153                                                 for (mp=mipparms ; mp->name ; mp++)
1154                                                 {
1155                                                         if (!strcmp(mp->name, token))
1156                                                         {
1157                                                                 if (mp->type == pt_gl)
1158                                                                 {
1159                                                                         dt_dst_blend_mode = mp->flags;
1160                                                                         break;
1161                                                                 }
1162                                                         }
1163                                                 }
1164                                                 if (!mp->name)
1165                                                 {
1166                                                         Error ("line %i: invalid gl blend mode %s", scriptline, token);
1167                                                 }
1168                                                 break;
1169                                 }
1170                                 break;
1171                         }
1172                 }
1173                 if (!mp->name)
1174                         Error ("line %i: unknown parm %s", scriptline, token);
1175         }
1176
1177         if (g_release)
1178                 return; // textures are only released by $maps
1179
1180         xh = xl+w;
1181         yh = yl+h;
1182         if (xh*yh > MAX_IMAGE_SIZE*MAX_IMAGE_SIZE)
1183         {
1184                 Error("line %i image %s: image is too big!", scriptline, lumpname);
1185         }
1186                 
1187         if (TrueColorImage)
1188         {
1189                 if (xl >= longimagewidth || xh > longimagewidth ||
1190                         yl >= longimageheight || yh > longimageheight)
1191                 {
1192                         Error ("line %i image %s: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, lumpname, xl,yl,w,h,longimagewidth,longimageheight);
1193                 }
1194
1195                 sourcel = longimage + (yl*longimagewidth) + xl;
1196                 destl = bufferl;
1197                 linedelta = (longimagewidth - w);
1198
1199                 for (y=yl ; y<yh ; y++)
1200                 {
1201                         for (x=xl ; x<xh ; x++)
1202                         {
1203                                 *destl++ = *sourcel++;  // RGBA
1204                         }
1205                         sourcel += linedelta;
1206                 }
1207
1208                 qtex32 = CreateMip32(bufferl, w, h, &size, true);
1209
1210                 qtex32->flags |= LittleLong(flags);
1211                 qtex32->flags2 |= LittleLong(flags2);
1212                 qtex32->contents = LittleLong(contents);
1213                 qtex32->value = LittleLong(value);
1214                 qtex32->scale_x = scale_x;
1215                 qtex32->scale_y = scale_y;
1216                 qtex32->mip_scale = mip_scale;
1217                 sprintf (qtex32->name, "%s/%s", mip_prefix, lumpname);
1218                 if (animname[0])
1219                 {
1220                         sprintf (qtex32->animname, "%s/%s", mip_prefix, animname);
1221                 }
1222                 if (altname[0])
1223                 {
1224                         sprintf (qtex32->altname, "%s/%s", mip_prefix, altname);
1225                 }
1226                 if (damagename[0])
1227                 {
1228                         sprintf (qtex32->damagename, "%s/%s", mip_prefix, damagename);
1229                 }
1230                 if (dt_name[0] & ((flags2 & MIP32_DETAILER_FLAG2) == 0)) 
1231                 {
1232                         sprintf (qtex32->dt_name, "%s/%s", mip_prefix, dt_name);
1233                         qtex32->dt_scale_x = dt_scale_x;
1234                         qtex32->dt_scale_y = dt_scale_y;
1235                         qtex32->dt_u = dt_u;
1236                         qtex32->dt_v = dt_v;
1237                         qtex32->dt_alpha = dt_alpha;
1238                         qtex32->dt_src_blend_mode = dt_src_blend_mode;
1239                         qtex32->dt_dst_blend_mode = dt_dst_blend_mode;
1240                 }
1241                 
1242         //
1243         // write it out
1244         //
1245                 sprintf (filename, "%stextures/%s/%s.m32", g_outputDir, mip_prefix, lumpname);
1246                 if(qtex32->flags & (SURF_ALPHA_TEXTURE))
1247                         printf ("writing %s with ALPHA\n", filename);
1248                 else
1249                         printf ("writing %s\n", filename);
1250                 SaveFile (filename, (byte *)qtex32, size);
1251
1252                 free (qtex32);
1253         }
1254         else
1255         {
1256                 if (xl >= byteimagewidth || xh > byteimagewidth ||
1257                         yl >= byteimageheight || yh > byteimageheight)
1258                 {
1259                         Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,byteimagewidth,byteimageheight);
1260                 }
1261
1262                 source = byteimage + yl*byteimagewidth + xl;
1263                 dest = buffer;
1264                 linedelta = byteimagewidth - w;
1265
1266                 for (y=yl ; y<yh ; y++)
1267                 {
1268                         for (x=xl ; x<xh ; x++)
1269                         {
1270                                 *dest++ = *source++;
1271                         }
1272                         source += linedelta;
1273                 }
1274
1275                 qtex = CreateMip(buffer, w, h, lbmpalette, &size, true);
1276
1277                 qtex->flags = LittleLong(flags);
1278                 qtex->contents = LittleLong(contents);
1279                 qtex->value = LittleLong(value);
1280                 sprintf (qtex->name, "%s/%s", mip_prefix, lumpname);
1281                 if (animname[0])
1282                         sprintf (qtex->animname, "%s/%s", mip_prefix, animname);
1283                 
1284         //
1285         // write it out
1286         //
1287                 sprintf (filename, "%stextures/%s/%s.m8", g_outputDir, mip_prefix, lumpname);
1288                 printf ("writing %s\n", filename);
1289                 SaveFile (filename, (byte *)qtex, size);
1290
1291                 free (qtex);
1292         }
1293 }
1294
1295 /*
1296 ===============
1297 Cmd_Mippal
1298 ===============
1299 */
1300 void Cmd_Mippal (void)
1301 {
1302         colormap_issued = true;
1303         if (g_release)
1304                 return;
1305
1306         memcpy (colormap_palette, lbmpalette, 768);
1307
1308         BuildPalmap();
1309 }
1310
1311
1312 /*
1313 ===============
1314 Cmd_Mipdir
1315 ===============
1316 */
1317 void Cmd_Mipdir (void)
1318 {
1319         char    filename[1024];
1320
1321         GetScriptToken (false);
1322         strcpy (mip_prefix, token);
1323         // create the directory if needed
1324         sprintf (filename, "%stextures", g_outputDir);
1325         Q_mkdir (filename); 
1326         sprintf (filename, "%stextures/%s", g_outputDir, mip_prefix);
1327         Q_mkdir (filename); 
1328 }
1329
1330
1331 /*
1332 =============================================================================
1333
1334 ENVIRONMENT MAP GRABBING
1335
1336 Creates six pcx files from tga files without any palette edge seams
1337 also copies the tga files for GL rendering.
1338 =============================================================================
1339 */
1340
1341 // 3dstudio environment map suffixes
1342 char    *suf[6] = {"rt", "ft", "lf", "bk", "up", "dn"};
1343
1344 /*
1345 =================
1346 Cmd_Environment
1347 =================
1348 */
1349 void Cmd_Environment (void)
1350 {
1351         char    name[1024];
1352         int             i, x, y;
1353         byte    image[256*256];
1354         byte    *tga;
1355
1356         GetScriptToken (false);
1357
1358         if (g_release)
1359         {
1360                 for (i=0 ; i<6 ; i++)
1361                 {
1362                         sprintf (name, "env/%s%s.pcx", token, suf[i]);
1363                         ReleaseFile (name);
1364                         sprintf (name, "env/%s%s.tga", token, suf[i]);
1365                         ReleaseFile (name);
1366                 }
1367                 return;
1368         }
1369         // get the palette
1370         BuildPalmap ();
1371
1372         sprintf (name, "%senv/", gamedir);
1373         CreatePath (name);
1374
1375         // convert the images
1376         for (i=0 ; i<6 ; i++)
1377         {
1378                 sprintf (name, "%senv/%s%s.tga", gamedir, token, suf[i]);
1379                 printf ("loading %s...\n", name);
1380                 LoadTGA (name, &tga, NULL, NULL);
1381
1382                 for (y=0 ; y<256 ; y++)
1383                 {
1384                         for (x=0 ; x<256 ; x++)
1385                         {
1386                                 image[y*256+x] = FindColor (tga[(y*256+x)*4+0],tga[(y*256+x)*4+1],tga[(y*256+x)*4+2]);
1387                         }
1388                 }
1389                 free (tga);
1390                 sprintf (name, "%senv/%s%s.pcx", gamedir, token, suf[i]);
1391                 if (FileTime (name) != -1)
1392                         printf ("%s already exists, not overwriting.\n", name);
1393                 else
1394                         WritePCXfile (name, image, 256, 256, colormap_palette);
1395         }
1396 }
1397