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