2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
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.
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.
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
25 char mip_prefix[1024]; // directory to dump the textures in
27 qboolean colormap_issued;
28 byte colormap_palette[768];
34 Replaces all 0 bytes in an image with the closest palette entry.
35 This is because NT won't let us change index 0, so any palette
36 animation leaves those pixels untouched.
39 void RemapZero( byte *pixels, byte *palette, int width, int height ){
46 for ( i = 1 ; i < 255 ; i++ )
48 value = palette[i * 3 + 0] + palette[i * 3 + 1] + palette[i * 3 + 2];
56 for ( i = 0 ; i < c ; i++ )
57 if ( pixels[i] == 0 ) {
66 $grab filename x y width height
69 void Cmd_Grab( void ){
77 if ( token[0] == '/' || token[0] == '\\' ) {
78 sprintf( savename, "%s%s.pcx", gamedir, token + 1 );
81 sprintf( savename, "%spics/%s.pcx", gamedir, token );
85 if ( token[0] == '/' || token[0] == '\\' ) {
86 sprintf( dest, "%s.pcx", token + 1 );
89 sprintf( dest, "pics/%s.pcx", token );
105 if ( xl < 0 || yl < 0 || w < 0 || h < 0 || xl + w > byteimagewidth || yl + h > byteimageheight ) {
106 Error( "GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h );
109 // crop it to the proper size
110 cropped = malloc( w * h );
111 for ( y = 0 ; y < h ; y++ )
113 memcpy( cropped + y * w, byteimage + ( y + yl ) * byteimagewidth + xl, w );
116 // save off the new image
117 printf( "saving %s\n", savename );
118 CreatePath( savename );
119 WritePCXfile( savename, cropped, w, h, lbmpalette );
128 $grab filename x y width height
131 void Cmd_Raw( void ){
139 sprintf( savename, "%s%s.lmp", gamedir, token );
142 sprintf( dest, "%s.lmp", token );
156 if ( xl < 0 || yl < 0 || w < 0 || h < 0 || xl + w > byteimagewidth || yl + h > byteimageheight ) {
157 Error( "GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h );
160 // crop it to the proper size
161 cropped = malloc( w * h );
162 for ( y = 0 ; y < h ; y++ )
164 memcpy( cropped + y * w, byteimage + ( y + yl ) * byteimagewidth + xl, w );
167 // save off the new image
168 printf( "saving %s\n", savename );
169 CreatePath( savename );
171 SaveFile( savename, cropped, w * h );
177 =============================================================================
181 =============================================================================
189 byte BestColor( int r, int g, int b, int start, int stop ){
192 int bestdistortion, distortion;
197 // let any color go to 0 as a last resort
199 bestdistortion = 256 * 256 * 4;
202 pal = colormap_palette + start * 3;
203 for ( i = start ; i <= stop ; i++ )
205 dr = r - (int)pal[0];
206 dg = g - (int)pal[1];
207 db = b - (int)pal[2];
209 distortion = dr * dr + dg * dg + db * db;
210 if ( distortion < bestdistortion ) {
212 return i; // perfect match
215 bestdistortion = distortion;
230 the brightes colormap is first in the table (FIXME: reverse this now?)
232 64 rows of 256 : lightmaps
233 256 rows of 256 : translucency table
236 void Cmd_Colormap( void ){
239 float frac, red, green, blue;
241 byte *cropped, *lump_p;
245 colormap_issued = true;
247 memcpy( colormap_palette, lbmpalette, 768 );
250 if ( !TokenAvailable() ) { // just setting colormap_issued
255 sprintf( savename, "%spics/%s.pcx", gamedir, token );
258 sprintf( dest, "pics/%s.pcx", token );
265 brights = 1; // ignore 255 (transparent)
267 cropped = malloc( ( levels + 256 ) * 256 );
271 for ( l = 0; l < levels; l++ )
273 frac = range - range * (float)l / ( levels - 1 );
274 for ( c = 0 ; c < 256 - brights ; c++ )
276 red = lbmpalette[c * 3];
277 green = lbmpalette[c * 3 + 1];
278 blue = lbmpalette[c * 3 + 2];
280 red = (int)( red * frac + 0.5 );
281 green = (int)( green * frac + 0.5 );
282 blue = (int)( blue * frac + 0.5 );
285 // note: 254 instead of 255 because 255 is the transparent color, and we
286 // don't want anything remapping to that
287 // don't use color 0, because NT can't remap that (or 255)
289 *lump_p++ = BestColor( red,green,blue, 1, 254 );
292 // fullbrights allways stay the same
293 for ( ; c < 256 ; c++ )
297 // 66% transparancy table
298 for ( l = 0; l < 255; l++ )
300 for ( c = 0 ; c < 255 ; c++ )
302 red = lbmpalette[c * 3] * 0.33 + lbmpalette[l * 3] * 0.66;
303 green = lbmpalette[c * 3 + 1] * 0.33 + lbmpalette[l * 3 + 1] * 0.66;
304 blue = lbmpalette[c * 3 + 2] * 0.33 + lbmpalette[l * 3 + 2] * 0.66;
306 *lump_p++ = BestColor( red,green,blue, 1, 254 );
310 for ( c = 0 ; c < 256 ; c++ )
313 // save off the new image
314 printf( "saving %s\n", savename );
315 CreatePath( savename );
316 WritePCXfile( savename, cropped, 256, levels + 256, lbmpalette );
322 =============================================================================
326 =============================================================================
331 int d_red, d_green, d_blue;
333 byte palmap[32][32][32];
334 qboolean palmap_built;
341 int FindColor( int r, int g, int b ){
363 bestcolor = BestColor( r, g, b, 0, 254 );
365 bestcolor = palmap[r >> 3][g >> 3][b >> 3];
372 void BuildPalmap( void ){
377 if ( palmap_built ) {
382 for ( r = 4 ; r < 256 ; r += 8 )
384 for ( g = 4 ; g < 256 ; g += 8 )
386 for ( b = 4 ; b < 256 ; b += 8 )
388 bestcolor = BestColor( r, g, b, 1, 254 );
389 palmap[r >> 3][g >> 3][b >> 3] = bestcolor;
395 if ( !colormap_issued ) {
396 Error( "You must issue a $colormap command first" );
406 byte AveragePixels( int count ){
418 for ( i = 0 ; i < count ; i++ )
422 r += lbmpalette[pix * 3];
423 g += lbmpalette[pix * 3 + 1];
424 b += lbmpalette[pix * 3 + 2];
438 // find the best color
440 bestcolor = FindColor( r, g, b );
443 pal = colormap_palette + bestcolor * 3;
444 d_red = r - (int)pal[0];
445 d_green = g - (int)pal[1];
446 d_blue = b - (int)pal[2];
467 mipparm_t mipparms[] =
469 // utility content attributes
470 {"water", CONTENTS_WATER, pt_contents},
471 {"slime", CONTENTS_SLIME, pt_contents}, // mildly damaging
472 {"lava", CONTENTS_LAVA, pt_contents}, // very damaging
473 {"window", CONTENTS_WINDOW, pt_contents}, // solid, but doesn't eat internal textures
474 {"mist", CONTENTS_MIST, pt_contents}, // non-solid window
475 {"origin", CONTENTS_ORIGIN, pt_contents}, // center of rotating brushes
476 {"playerclip", CONTENTS_PLAYERCLIP, pt_contents},
477 {"monsterclip", CONTENTS_MONSTERCLIP, pt_contents},
479 // utility surface attributes
480 {"hint", SURF_HINT, pt_flags},
481 {"skip", SURF_SKIP, pt_flags},
482 {"light", SURF_LIGHT, pt_flagvalue}, // value is the light quantity
485 {"anim", 0, pt_animvalue}, // value is the next animation
488 {"slick", SURF_SLICK, pt_flags},
490 // drawing attributes
491 {"sky", SURF_SKY, pt_flags},
492 {"warping", SURF_WARP, pt_flags}, // only valid with 64x64 textures
493 {"trans33", SURF_TRANS33, pt_flags}, // translucent should allso set fullbright
494 {"trans66", SURF_TRANS66, pt_flags},
495 {"flowing", SURF_FLOWING, pt_flags}, // flow direction towards angle 0
496 {"nodraw", SURF_NODRAW, pt_flags}, // for clip textures and trigger textures
498 {NULL, 0, pt_contents}
507 $mip filename x y width height <OPTIONS>
508 must be multiples of sixteen
512 void Cmd_Mip( void ){
513 int x,y,xl,yl,xh,yh,w,h;
514 byte *screen_p, *source;
517 int miplevel, mipstep;
520 int flags, value, contents;
528 strcpy( lumpname, token );
539 if ( ( w & 15 ) || ( h & 15 ) ) {
540 Error( "line %i: miptex sizes must be multiples of 16", scriptline );
549 // get optional flags and values
550 while ( TokenAvailable() )
554 for ( mp = mipparms ; mp->name ; mp++ )
556 if ( !strcmp( mp->name, token ) ) {
560 GetToken( false ); // specify the next animation frame
561 strcpy( animname, token );
567 contents |= mp->flags;
571 GetToken( false ); // specify the light value
572 value = atoi( token );
579 Error( "line %i: unknown parm %s", scriptline, token );
583 sprintf( filename, "%stextures/%s/%s.wal", gamedir, mip_prefix, lumpname );
585 return; // textures are only released by $maps
591 qtex = malloc( sizeof( miptex_t ) + w * h * 2 );
592 memset( qtex, 0, sizeof( miptex_t ) );
594 qtex->width = LittleLong( w );
595 qtex->height = LittleLong( h );
596 qtex->flags = LittleLong( flags );
597 qtex->contents = LittleLong( contents );
598 qtex->value = LittleLong( value );
599 sprintf( qtex->name, "%s/%s", mip_prefix, lumpname );
601 sprintf( qtex->animname, "%s/%s", mip_prefix, animname );
604 lump_p = (byte *)( &qtex->value + 1 );
606 screen_p = byteimage + yl * byteimagewidth + xl;
607 linedelta = byteimagewidth - w;
610 qtex->offsets[0] = LittleLong( lump_p - (byte *)qtex );
612 for ( y = yl ; y < yh ; y++ )
614 for ( x = xl ; x < xh ; x++ )
618 pix = 1; // should never happen
622 screen_p += linedelta;
626 // subsample for greater mip levels
628 d_red = d_green = d_blue = 0; // no distortion yet
630 for ( miplevel = 1 ; miplevel < 4 ; miplevel++ )
632 qtex->offsets[miplevel] = LittleLong( lump_p - (byte *)qtex );
634 mipstep = 1 << miplevel;
635 for ( y = 0 ; y < h ; y += mipstep )
638 for ( x = 0 ; x < w ; x += mipstep )
641 for ( yy = 0 ; yy < mipstep ; yy++ )
642 for ( xx = 0 ; xx < mipstep ; xx++ )
644 pixdata[count] = source[ ( y + yy ) * w + x + xx ];
647 *lump_p++ = AveragePixels( count );
653 // dword align the size
655 while ( (int)lump_p & 3 )
661 printf( "writing %s\n", filename );
662 SaveFile( filename, (byte *)qtex, lump_p - (byte *)qtex );
672 void Cmd_Mippal( void ){
673 colormap_issued = true;
678 memcpy( colormap_palette, lbmpalette, 768 );
689 void Cmd_Mipdir( void ){
693 strcpy( mip_prefix, token );
694 // create the directory if needed
695 sprintf( filename, "%stextures", gamedir, mip_prefix );
697 sprintf( filename, "%stextures/%s", gamedir, mip_prefix );
703 =============================================================================
705 ENVIRONMENT MAP GRABBING
707 Creates six pcx files from tga files without any palette edge seams
708 also copies the tga files for GL rendering.
709 =============================================================================
712 // 3dstudio environment map suffixes
713 char *suf[6] = {"rt", "ft", "lf", "bk", "up", "dn"};
720 void Cmd_Environment( void ){
723 byte image[256 * 256];
729 for ( i = 0 ; i < 6 ; i++ )
731 sprintf( name, "env/%s%s.pcx", token, suf[i] );
733 sprintf( name, "env/%s%s.tga", token, suf[i] );
741 sprintf( name, "%senv/", gamedir );
744 // convert the images
745 for ( i = 0 ; i < 6 ; i++ )
747 sprintf( name, "%senv/%s%s.tga", gamedir, token, suf[i] );
748 printf( "loading %s...\n", name );
749 LoadTGA( name, &tga, NULL, NULL );
751 for ( y = 0 ; y < 256 ; y++ )
753 for ( x = 0 ; x < 256 ; x++ )
755 image[y * 256 + x] = FindColor( tga[( y * 256 + x ) * 4 + 0],tga[( y * 256 + x ) * 4 + 1],tga[( y * 256 + x ) * 4 + 2] );
759 sprintf( name, "%senv/%s%s.pcx", gamedir, token, suf[i] );
760 if ( FileTime( name ) != -1 ) {
761 printf( "%s already exists, not overwriting.\n", name );
764 WritePCXfile( name, image, 256, 256, colormap_palette );