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