1 /* -------------------------------------------------------------------------------;
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
6 This file is part of GtkRadiant.
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 -------------------------------------------------------------------------------
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
27 ------------------------------------------------------------------------------- */
43 returns a pseudorandom number between 0 and 1
47 return (vec_t) rand() / RAND_MAX;
57 static void ExitQ3Map( void ){
59 if ( mapDrawSurfs != NULL ) {
68 typedef struct minimap_s
74 float *sample_offsets;
75 float sharpen_boxmult;
76 float sharpen_centermult;
77 float boost, brightness, contrast;
83 static minimap_t minimap;
85 qboolean BrushIntersectionWithLine( bspBrush_t *brush, vec3_t start, vec3_t dir, float *t_in, float *t_out ){
87 qboolean in = qfalse, out = qfalse;
88 bspBrushSide_t *sides = &bspBrushSides[brush->firstSide];
90 for ( i = 0; i < brush->numSides; ++i )
92 bspPlane_t *p = &bspPlanes[sides[i].planeNum];
93 float sn = DotProduct( start, p->normal );
94 float dn = DotProduct( dir, p->normal );
97 return qfalse; // outside!
102 float t = ( p->dist - sn ) / dn;
104 if ( !in || t > *t_in ) {
107 // as t_in can only increase, and t_out can only decrease, early out
108 if ( out && *t_in >= *t_out ) {
115 if ( !out || t < *t_out ) {
118 // as t_in can only increase, and t_out can only decrease, early out
119 if ( in && *t_in >= *t_out ) {
129 static float MiniMapSample( float x, float y ){
147 for ( i = 0; i < minimap.model->numBSPBrushes; ++i )
149 bi = minimap.model->firstBSPBrush + i;
150 if ( opaqueBrushes[bi >> 3] & ( 1 << ( bi & 7 ) ) ) {
153 // sort out mins/maxs of the brush
154 s = &bspBrushSides[b->firstSide];
155 if ( x < -bspPlanes[s[0].planeNum].dist ) {
158 if ( x > +bspPlanes[s[1].planeNum].dist ) {
161 if ( y < -bspPlanes[s[2].planeNum].dist ) {
164 if ( y > +bspPlanes[s[3].planeNum].dist ) {
168 if ( BrushIntersectionWithLine( b, org, dir, &t0, &t1 ) ) {
178 void RandomVector2f( float v[2] ){
181 v[0] = 2 * Random() - 1;
182 v[1] = 2 * Random() - 1;
184 while ( v[0] * v[0] + v[1] * v[1] > 1 );
187 static void MiniMapRandomlySupersampled( int y ){
189 float *p = &minimap.data1f[y * minimap.width];
190 float ymin = minimap.mins[1] + minimap.size[1] * ( y / (float) minimap.height );
191 float dx = minimap.size[0] / (float) minimap.width;
192 float dy = minimap.size[1] / (float) minimap.height;
196 for ( x = 0; x < minimap.width; ++x )
198 float xmin = minimap.mins[0] + minimap.size[0] * ( x / (float) minimap.width );
201 for ( i = 0; i < minimap.samples; ++i )
203 RandomVector2f( uv );
204 thisval = MiniMapSample(
205 xmin + ( uv[0] + 0.5 ) * dx, /* exaggerated random pattern for better results */
206 ymin + ( uv[1] + 0.5 ) * dy /* exaggerated random pattern for better results */
210 val /= minimap.samples * minimap.size[2];
215 static void MiniMapSupersampled( int y ){
217 float *p = &minimap.data1f[y * minimap.width];
218 float ymin = minimap.mins[1] + minimap.size[1] * ( y / (float) minimap.height );
219 float dx = minimap.size[0] / (float) minimap.width;
220 float dy = minimap.size[1] / (float) minimap.height;
222 for ( x = 0; x < minimap.width; ++x )
224 float xmin = minimap.mins[0] + minimap.size[0] * ( x / (float) minimap.width );
227 for ( i = 0; i < minimap.samples; ++i )
229 float thisval = MiniMapSample(
230 xmin + minimap.sample_offsets[2 * i + 0] * dx,
231 ymin + minimap.sample_offsets[2 * i + 1] * dy
235 val /= minimap.samples * minimap.size[2];
240 static void MiniMapNoSupersampling( int y ){
242 float *p = &minimap.data1f[y * minimap.width];
243 float ymin = minimap.mins[1] + minimap.size[1] * ( ( y + 0.5 ) / (float) minimap.height );
245 for ( x = 0; x < minimap.width; ++x )
247 float xmin = minimap.mins[0] + minimap.size[0] * ( ( x + 0.5 ) / (float) minimap.width );
248 *p++ = MiniMapSample( xmin, ymin ) / minimap.size[2];
252 static void MiniMapSharpen( int y ){
254 qboolean up = ( y > 0 );
255 qboolean down = ( y < minimap.height - 1 );
256 float *p = &minimap.data1f[y * minimap.width];
257 float *q = &minimap.sharpendata1f[y * minimap.width];
259 for ( x = 0; x < minimap.width; ++x )
261 qboolean left = ( x > 0 );
262 qboolean right = ( x < minimap.width - 1 );
263 float val = p[0] * minimap.sharpen_centermult;
266 val += p[-1 - minimap.width] * minimap.sharpen_boxmult;
268 if ( left && down ) {
269 val += p[-1 + minimap.width] * minimap.sharpen_boxmult;
272 val += p[+1 - minimap.width] * minimap.sharpen_boxmult;
274 if ( right && down ) {
275 val += p[+1 + minimap.width] * minimap.sharpen_boxmult;
279 val += p[-1] * minimap.sharpen_boxmult;
282 val += p[+1] * minimap.sharpen_boxmult;
285 val += p[-minimap.width] * minimap.sharpen_boxmult;
288 val += p[+minimap.width] * minimap.sharpen_boxmult;
296 static void MiniMapContrastBoost( int y ){
298 float *q = &minimap.data1f[y * minimap.width];
299 for ( x = 0; x < minimap.width; ++x )
301 *q = *q * minimap.boost / ( ( minimap.boost - 1 ) * *q + 1 );
306 static void MiniMapBrightnessContrast( int y ){
308 float *q = &minimap.data1f[y * minimap.width];
309 for ( x = 0; x < minimap.width; ++x )
311 *q = *q * minimap.contrast + minimap.brightness;
316 void MiniMapMakeMinsMaxs( vec3_t mins_in, vec3_t maxs_in, float border, qboolean keepaspect ){
317 vec3_t mins, maxs, extend;
318 VectorCopy( mins_in, mins );
319 VectorCopy( maxs_in, maxs );
321 // line compatible to nexuiz mapinfo
322 Sys_Printf( "size %f %f %f %f %f %f\n", mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2] );
325 VectorSubtract( maxs, mins, extend );
326 if ( extend[1] > extend[0] ) {
327 mins[0] -= ( extend[1] - extend[0] ) * 0.5;
328 maxs[0] += ( extend[1] - extend[0] ) * 0.5;
332 mins[1] -= ( extend[0] - extend[1] ) * 0.5;
333 maxs[1] += ( extend[0] - extend[1] ) * 0.5;
337 /* border: amount of black area around the image */
338 /* input: border, 1-2*border, border but we need border/(1-2*border) */
340 VectorSubtract( maxs, mins, extend );
341 VectorScale( extend, border / ( 1 - 2 * border ), extend );
343 VectorSubtract( mins, extend, mins );
344 VectorAdd( maxs, extend, maxs );
346 VectorCopy( mins, minimap.mins );
347 VectorSubtract( maxs, mins, minimap.size );
349 // line compatible to nexuiz mapinfo
350 Sys_Printf( "size_texcoords %f %f %f %f %f %f\n", mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2] );
354 MiniMapSetupBrushes()
355 determines solid non-sky brushes in the world
358 void MiniMapSetupBrushes( void ){
359 SetupBrushesFlags( C_SOLID | C_SKY, C_SOLID, 0, 0 );
360 // at least one must be solid
362 // not all may be nodraw
365 qboolean MiniMapEvaluateSampleOffsets( int *bestj, int *bestk, float *bestval ){
369 *bestj = *bestk = -1;
370 *bestval = 3; /* max possible val is 2 */
372 for ( j = 0; j < minimap.samples; ++j )
373 for ( k = j + 1; k < minimap.samples; ++k )
375 dx = minimap.sample_offsets[2 * j + 0] - minimap.sample_offsets[2 * k + 0];
376 dy = minimap.sample_offsets[2 * j + 1] - minimap.sample_offsets[2 * k + 1];
389 val = dx * dx + dy * dy;
390 if ( val < *bestval ) {
400 void MiniMapMakeSampleOffsets(){
402 float val, valj, valk, sx, sy, rx, ry;
404 Sys_Printf( "Generating good sample offsets (this may take a while)...\n" );
406 /* start with entirely random samples */
407 for ( i = 0; i < minimap.samples; ++i )
409 minimap.sample_offsets[2 * i + 0] = Random();
410 minimap.sample_offsets[2 * i + 1] = Random();
413 for ( i = 0; i < 1000; ++i )
415 if ( MiniMapEvaluateSampleOffsets( &j, &k, &val ) ) {
416 sx = minimap.sample_offsets[2 * j + 0];
417 sy = minimap.sample_offsets[2 * j + 1];
418 minimap.sample_offsets[2 * j + 0] = rx = Random();
419 minimap.sample_offsets[2 * j + 1] = ry = Random();
420 if ( !MiniMapEvaluateSampleOffsets( &jj, &kk, &valj ) ) {
423 minimap.sample_offsets[2 * j + 0] = sx;
424 minimap.sample_offsets[2 * j + 1] = sy;
426 sx = minimap.sample_offsets[2 * k + 0];
427 sy = minimap.sample_offsets[2 * k + 1];
428 minimap.sample_offsets[2 * k + 0] = rx;
429 minimap.sample_offsets[2 * k + 1] = ry;
430 if ( !MiniMapEvaluateSampleOffsets( &jj, &kk, &valk ) ) {
433 minimap.sample_offsets[2 * k + 0] = sx;
434 minimap.sample_offsets[2 * k + 1] = sy;
438 /* valj is the greatest */
439 minimap.sample_offsets[2 * j + 0] = rx;
440 minimap.sample_offsets[2 * j + 1] = ry;
445 /* valj is the greater and it is useless - forget it */
451 /* valk is the greatest */
452 minimap.sample_offsets[2 * k + 0] = rx;
453 minimap.sample_offsets[2 * k + 1] = ry;
458 /* valk is the greater and it is useless - forget it */
468 void MergeRelativePath( char *out, const char *absolute, const char *relative ){
469 const char *endpos = absolute + strlen( absolute );
470 while ( endpos != absolute && ( endpos[-1] == '/' || endpos[-1] == '\\' ) )
472 while ( relative[0] == '.' && relative[1] == '.' && ( relative[2] == '/' || relative[2] == '\\' ) )
475 while ( endpos != absolute )
478 if ( *endpos == '/' || *endpos == '\\' ) {
482 while ( endpos != absolute && ( endpos[-1] == '/' || endpos[-1] == '\\' ) )
485 memcpy( out, absolute, endpos - absolute );
486 out[endpos - absolute] = '/';
487 strcpy( out + ( endpos - absolute + 1 ), relative );
490 int MiniMapBSPMain( int argc, char **argv ){
491 char minimapFilename[1024];
494 char relativeMinimapFilename[1024];
496 float minimapSharpen;
508 Sys_Printf( "Usage: q3map [-v] -minimap [-size n] [-sharpen f] [-samples n | -random n] [-o filename.tga] [-minmax Xmin Ymin Zmin Xmax Ymax Zmax] <mapname>\n" );
512 /* load the BSP first */
513 strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
514 StripExtension( source );
515 DefaultExtension( source, ".bsp" );
516 Sys_Printf( "Loading %s\n", source );
517 BeginMapShaderFile( source );
519 LoadBSPFile( source );
521 minimap.model = &bspModels[0];
522 VectorCopy( minimap.model->mins, mins );
523 VectorCopy( minimap.model->maxs, maxs );
525 *minimapFilename = 0;
526 minimapSharpen = game->miniMapSharpen;
527 minimap.width = minimap.height = game->miniMapSize;
528 border = game->miniMapBorder;
529 keepaspect = game->miniMapKeepAspect;
530 mode = game->miniMapMode;
534 minimap.sample_offsets = NULL;
536 minimap.brightness = 0.0;
537 minimap.contrast = 1.0;
539 /* process arguments */
540 for ( i = 1; i < ( argc - 1 ); i++ )
542 if ( !strcmp( argv[ i ], "-size" ) ) {
543 minimap.width = minimap.height = atoi( argv[i + 1] );
545 Sys_Printf( "Image size set to %i\n", minimap.width );
547 else if ( !strcmp( argv[ i ], "-sharpen" ) ) {
548 minimapSharpen = atof( argv[i + 1] );
550 Sys_Printf( "Sharpening coefficient set to %f\n", minimapSharpen );
552 else if ( !strcmp( argv[ i ], "-samples" ) ) {
553 minimap.samples = atoi( argv[i + 1] );
555 Sys_Printf( "Samples set to %i\n", minimap.samples );
556 if ( minimap.sample_offsets ) {
557 free( minimap.sample_offsets );
559 minimap.sample_offsets = malloc( 2 * sizeof( *minimap.sample_offsets ) * minimap.samples );
560 MiniMapMakeSampleOffsets();
562 else if ( !strcmp( argv[ i ], "-random" ) ) {
563 minimap.samples = atoi( argv[i + 1] );
565 Sys_Printf( "Random samples set to %i\n", minimap.samples );
566 if ( minimap.sample_offsets ) {
567 free( minimap.sample_offsets );
569 minimap.sample_offsets = NULL;
571 else if ( !strcmp( argv[ i ], "-border" ) ) {
572 border = atof( argv[i + 1] );
574 Sys_Printf( "Border set to %f\n", border );
576 else if ( !strcmp( argv[ i ], "-keepaspect" ) ) {
578 Sys_Printf( "Keeping aspect ratio by letterboxing\n", border );
580 else if ( !strcmp( argv[ i ], "-nokeepaspect" ) ) {
582 Sys_Printf( "Not keeping aspect ratio\n", border );
584 else if ( !strcmp( argv[ i ], "-o" ) ) {
585 strcpy( minimapFilename, argv[i + 1] );
587 Sys_Printf( "Output file name set to %s\n", minimapFilename );
589 else if ( !strcmp( argv[ i ], "-minmax" ) && i < ( argc - 7 ) ) {
590 mins[0] = atof( argv[i + 1] );
591 mins[1] = atof( argv[i + 2] );
592 mins[2] = atof( argv[i + 3] );
593 maxs[0] = atof( argv[i + 4] );
594 maxs[1] = atof( argv[i + 5] );
595 maxs[2] = atof( argv[i + 6] );
597 Sys_Printf( "Map mins/maxs overridden\n" );
599 else if ( !strcmp( argv[ i ], "-gray" ) ) {
600 mode = MINIMAP_MODE_GRAY;
601 Sys_Printf( "Writing as white-on-black image\n" );
603 else if ( !strcmp( argv[ i ], "-black" ) ) {
604 mode = MINIMAP_MODE_BLACK;
605 Sys_Printf( "Writing as black alpha image\n" );
607 else if ( !strcmp( argv[ i ], "-white" ) ) {
608 mode = MINIMAP_MODE_WHITE;
609 Sys_Printf( "Writing as white alpha image\n" );
611 else if ( !strcmp( argv[ i ], "-boost" ) && i < ( argc - 2 ) ) {
612 minimap.boost = atof( argv[i + 1] );
614 Sys_Printf( "Contrast boost set to %f\n", minimap.boost );
616 else if ( !strcmp( argv[ i ], "-brightness" ) && i < ( argc - 2 ) ) {
617 minimap.brightness = atof( argv[i + 1] );
619 Sys_Printf( "Brightness set to %f\n", minimap.brightness );
621 else if ( !strcmp( argv[ i ], "-contrast" ) && i < ( argc - 2 ) ) {
622 minimap.contrast = atof( argv[i + 1] );
624 Sys_Printf( "Contrast set to %f\n", minimap.contrast );
626 else if ( !strcmp( argv[ i ], "-autolevel" ) ) {
628 Sys_Printf( "Auto level enabled\n", border );
630 else if ( !strcmp( argv[ i ], "-noautolevel" ) ) {
632 Sys_Printf( "Auto level disabled\n", border );
636 MiniMapMakeMinsMaxs( mins, maxs, border, keepaspect );
638 if ( !*minimapFilename ) {
639 ExtractFileBase( source, basename );
640 ExtractFilePath( source, path );
641 sprintf( relativeMinimapFilename, game->miniMapNameFormat, basename );
642 MergeRelativePath( minimapFilename, path, relativeMinimapFilename );
643 Sys_Printf( "Output file name automatically set to %s\n", minimapFilename );
645 ExtractFilePath( minimapFilename, path );
648 if ( minimapSharpen >= 0 ) {
649 minimap.sharpen_centermult = 8 * minimapSharpen + 1;
650 minimap.sharpen_boxmult = -minimapSharpen;
653 minimap.data1f = safe_malloc( minimap.width * minimap.height * sizeof( *minimap.data1f ) );
654 data4b = safe_malloc( minimap.width * minimap.height * 4 );
655 if ( minimapSharpen >= 0 ) {
656 minimap.sharpendata1f = safe_malloc( minimap.width * minimap.height * sizeof( *minimap.data1f ) );
659 MiniMapSetupBrushes();
661 if ( minimap.samples <= 1 ) {
662 Sys_Printf( "\n--- MiniMapNoSupersampling (%d) ---\n", minimap.height );
663 RunThreadsOnIndividual( minimap.height, qtrue, MiniMapNoSupersampling );
667 if ( minimap.sample_offsets ) {
668 Sys_Printf( "\n--- MiniMapSupersampled (%d) ---\n", minimap.height );
669 RunThreadsOnIndividual( minimap.height, qtrue, MiniMapSupersampled );
673 Sys_Printf( "\n--- MiniMapRandomlySupersampled (%d) ---\n", minimap.height );
674 RunThreadsOnIndividual( minimap.height, qtrue, MiniMapRandomlySupersampled );
678 if ( minimap.boost != 1.0 ) {
679 Sys_Printf( "\n--- MiniMapContrastBoost (%d) ---\n", minimap.height );
680 RunThreadsOnIndividual( minimap.height, qtrue, MiniMapContrastBoost );
684 Sys_Printf( "\n--- MiniMapAutoLevel (%d) ---\n", minimap.height );
685 float mi = 1, ma = 0;
690 for ( y = 0; y < minimap.height; ++y )
691 for ( x = 0; x < minimap.width; ++x )
703 o = mi / ( ma - mi );
706 // brightness + contrast * v
708 // brightness + contrast * (v * s - o)
710 // (brightness - contrast * o) + (contrast * s) * v
711 minimap.brightness = minimap.brightness - minimap.contrast * o;
712 minimap.contrast *= s;
714 Sys_Printf( "Auto level: Brightness changed to %f\n", minimap.brightness );
715 Sys_Printf( "Auto level: Contrast changed to %f\n", minimap.contrast );
718 Sys_Printf( "Auto level: failed because all pixels are the same value\n" );
722 if ( minimap.brightness != 0 || minimap.contrast != 1 ) {
723 Sys_Printf( "\n--- MiniMapBrightnessContrast (%d) ---\n", minimap.height );
724 RunThreadsOnIndividual( minimap.height, qtrue, MiniMapBrightnessContrast );
727 if ( minimap.sharpendata1f ) {
728 Sys_Printf( "\n--- MiniMapSharpen (%d) ---\n", minimap.height );
729 RunThreadsOnIndividual( minimap.height, qtrue, MiniMapSharpen );
730 q = minimap.sharpendata1f;
737 Sys_Printf( "\nConverting..." );
741 case MINIMAP_MODE_GRAY:
743 for ( y = 0; y < minimap.height; ++y )
744 for ( x = 0; x < minimap.width; ++x )
751 if ( v > 255.0 / 256.0 ) {
757 Sys_Printf( " writing to %s...", minimapFilename );
758 WriteTGAGray( minimapFilename, data4b, minimap.width, minimap.height );
760 case MINIMAP_MODE_BLACK:
762 for ( y = 0; y < minimap.height; ++y )
763 for ( x = 0; x < minimap.width; ++x )
770 if ( v > 255.0 / 256.0 ) {
779 Sys_Printf( " writing to %s...", minimapFilename );
780 WriteTGA( minimapFilename, data4b, minimap.width, minimap.height );
782 case MINIMAP_MODE_WHITE:
784 for ( y = 0; y < minimap.height; ++y )
785 for ( x = 0; x < minimap.width; ++x )
792 if ( v > 255.0 / 256.0 ) {
801 Sys_Printf( " writing to %s...", minimapFilename );
802 WriteTGA( minimapFilename, data4b, minimap.width, minimap.height );
806 Sys_Printf( " done.\n" );
808 /* return to sender */
818 calculates an md4 checksum for a block of data
821 static int MD4BlockChecksum( void *buffer, int length ){
822 return Com_BlockChecksum( buffer, length );
827 resets an aas checksum to match the given BSP
830 int FixAAS( int argc, char **argv ){
831 int length, checksum;
834 char aas[ 1024 ], **ext;
846 Sys_Printf( "Usage: q3map -fixaas [-v] <mapname>\n" );
850 /* do some path mangling */
851 strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
852 StripExtension( source );
853 DefaultExtension( source, ".bsp" );
856 Sys_Printf( "--- FixAAS ---\n" );
859 Sys_Printf( "Loading %s\n", source );
860 length = LoadFile( source, &buffer );
862 /* create bsp checksum */
863 Sys_Printf( "Creating checksum...\n" );
864 checksum = LittleLong( MD4BlockChecksum( buffer, length ) );
866 /* write checksum to aas */
871 strcpy( aas, source );
872 StripExtension( aas );
874 Sys_Printf( "Trying %s\n", aas );
878 file = fopen( aas, "r+b" );
882 if ( fwrite( &checksum, 4, 1, file ) != 1 ) {
883 Error( "Error writing checksum to %s", aas );
888 /* return to sender */
896 analyzes a Quake engine BSP file
899 typedef struct abspHeader_s
904 bspLump_t lumps[ 1 ]; /* unknown size */
908 typedef struct abspLumpTest_s
915 int AnalyzeBSP( int argc, char **argv ){
916 abspHeader_t *header;
917 int size, i, version, offset, length, lumpInt, count;
921 char lumpString[ 1024 ], source[ 1024 ];
922 qboolean lumpSwap = qfalse;
923 abspLumpTest_t *lumpTest;
924 static abspLumpTest_t lumpTests[] =
926 { sizeof( bspPlane_t ), 6, "IBSP LUMP_PLANES" },
927 { sizeof( bspBrush_t ), 1, "IBSP LUMP_BRUSHES" },
928 { 8, 6, "IBSP LUMP_BRUSHSIDES" },
929 { sizeof( bspBrushSide_t ), 6, "RBSP LUMP_BRUSHSIDES" },
930 { sizeof( bspModel_t ), 1, "IBSP LUMP_MODELS" },
931 { sizeof( bspNode_t ), 2, "IBSP LUMP_NODES" },
932 { sizeof( bspLeaf_t ), 1, "IBSP LUMP_LEAFS" },
933 { 104, 3, "IBSP LUMP_DRAWSURFS" },
934 { 44, 3, "IBSP LUMP_DRAWVERTS" },
935 { 4, 6, "IBSP LUMP_DRAWINDEXES" },
936 { 128 * 128 * 3, 1, "IBSP LUMP_LIGHTMAPS" },
937 { 256 * 256 * 3, 1, "IBSP LUMP_LIGHTMAPS (256 x 256)" },
938 { 512 * 512 * 3, 1, "IBSP LUMP_LIGHTMAPS (512 x 512)" },
945 Sys_Printf( "Usage: q3map -analyze [-lumpswap] [-v] <mapname>\n" );
949 /* process arguments */
950 for ( i = 1; i < ( argc - 1 ); i++ )
952 /* -format map|ase|... */
953 if ( !strcmp( argv[ i ], "-lumpswap" ) ) {
954 Sys_Printf( "Swapped lump structs enabled\n" );
959 /* clean up map name */
960 strcpy( source, ExpandArg( argv[ i ] ) );
961 Sys_Printf( "Loading %s\n", source );
964 size = LoadFile( source, (void**) &header );
965 if ( size == 0 || header == NULL ) {
966 Sys_Printf( "Unable to load %s.\n", source );
970 /* analyze ident/version */
971 memcpy( ident, header->ident, 4 );
973 version = LittleLong( header->version );
975 Sys_Printf( "Identity: %s\n", ident );
976 Sys_Printf( "Version: %d\n", version );
977 Sys_Printf( "---------------------------------------\n" );
979 /* analyze each lump */
980 for ( i = 0; i < 100; i++ )
982 /* call of duty swapped lump pairs */
984 offset = LittleLong( header->lumps[ i ].length );
985 length = LittleLong( header->lumps[ i ].offset );
988 /* standard lump pairs */
991 offset = LittleLong( header->lumps[ i ].offset );
992 length = LittleLong( header->lumps[ i ].length );
996 lump = (byte*) header + offset;
997 lumpInt = LittleLong( (int) *( (int*) lump ) );
998 lumpFloat = LittleFloat( (float) *( (float*) lump ) );
999 memcpy( lumpString, (char*) lump, ( (size_t)length < sizeof( lumpString ) ? (size_t)length : sizeof( lumpString ) - 1 ) );
1000 lumpString[ sizeof( lumpString ) - 1 ] = '\0';
1002 /* print basic lump info */
1003 Sys_Printf( "Lump: %d\n", i );
1004 Sys_Printf( "Offset: %d bytes\n", offset );
1005 Sys_Printf( "Length: %d bytes\n", length );
1007 /* only operate on valid lumps */
1009 /* print data in 4 formats */
1010 Sys_Printf( "As hex: %08X\n", lumpInt );
1011 Sys_Printf( "As int: %d\n", lumpInt );
1012 Sys_Printf( "As float: %f\n", lumpFloat );
1013 Sys_Printf( "As string: %s\n", lumpString );
1015 /* guess lump type */
1016 if ( lumpString[ 0 ] == '{' && lumpString[ 2 ] == '"' ) {
1017 Sys_Printf( "Type guess: IBSP LUMP_ENTITIES\n" );
1019 else if ( strstr( lumpString, "textures/" ) ) {
1020 Sys_Printf( "Type guess: IBSP LUMP_SHADERS\n" );
1024 /* guess based on size/count */
1025 for ( lumpTest = lumpTests; lumpTest->radix > 0; lumpTest++ )
1027 if ( ( length % lumpTest->radix ) != 0 ) {
1030 count = length / lumpTest->radix;
1031 if ( count < lumpTest->minCount ) {
1034 Sys_Printf( "Type guess: %s (%d x %d)\n", lumpTest->name, count, lumpTest->radix );
1039 Sys_Printf( "---------------------------------------\n" );
1042 if ( offset + length >= size ) {
1048 Sys_Printf( "Lump count: %d\n", i + 1 );
1049 Sys_Printf( "File size: %d bytes\n", size );
1051 /* return to caller */
1059 emits statistics about the bsp file
1062 int BSPInfo( int count, char **fileNames ){
1064 char source[ 1024 ], ext[ 64 ];
1071 Sys_Printf( "No files to dump info for.\n" );
1075 /* enable info mode */
1078 /* walk file list */
1079 for ( i = 0; i < count; i++ )
1081 Sys_Printf( "---------------------------------\n" );
1083 /* mangle filename and get size */
1084 strcpy( source, fileNames[ i ] );
1085 ExtractFileExtension( source, ext );
1086 if ( !Q_stricmp( ext, "map" ) ) {
1087 StripExtension( source );
1089 DefaultExtension( source, ".bsp" );
1090 f = fopen( source, "rb" );
1092 size = Q_filelength( f );
1099 /* load the bsp file and print lump sizes */
1100 Sys_Printf( "%s\n", source );
1101 LoadBSPFile( source );
1102 PrintBSPFileSizes();
1106 Sys_Printf( " total %9d\n", size );
1107 Sys_Printf( " %9d KB\n", size / 1024 );
1108 Sys_Printf( " %9d MB\n", size / ( 1024 * 1024 ) );
1110 Sys_Printf( "---------------------------------\n" );
1118 static void ExtrapolateTexcoords( const float *axyz, const float *ast, const float *bxyz, const float *bst, const float *cxyz, const float *cst, const float *axyz_new, float *ast_out, const float *bxyz_new, float *bst_out, const float *cxyz_new, float *cst_out ){
1119 vec4_t scoeffs, tcoeffs;
1125 VectorSubtract( bxyz, axyz, dab );
1126 VectorSubtract( cxyz, axyz, dac );
1127 CrossProduct( dab, dac, norm );
1131 // s(v + norm) = s(v) when n ortho xyz
1133 // s(v) = DotProduct(v, scoeffs) + scoeffs[3]
1136 // scoeffs * (axyz, 1) == ast[0]
1137 // scoeffs * (bxyz, 1) == bst[0]
1138 // scoeffs * (cxyz, 1) == cst[0]
1139 // scoeffs * (norm, 0) == 0
1140 // scoeffs * [axyz, 1 | bxyz, 1 | cxyz, 1 | norm, 0] = [ast[0], bst[0], cst[0], 0]
1141 solvematrix[0] = axyz[0];
1142 solvematrix[4] = axyz[1];
1143 solvematrix[8] = axyz[2];
1144 solvematrix[12] = 1;
1145 solvematrix[1] = bxyz[0];
1146 solvematrix[5] = bxyz[1];
1147 solvematrix[9] = bxyz[2];
1148 solvematrix[13] = 1;
1149 solvematrix[2] = cxyz[0];
1150 solvematrix[6] = cxyz[1];
1151 solvematrix[10] = cxyz[2];
1152 solvematrix[14] = 1;
1153 solvematrix[3] = norm[0];
1154 solvematrix[7] = norm[1];
1155 solvematrix[11] = norm[2];
1156 solvematrix[15] = 0;
1158 md = m4_det( solvematrix );
1159 if ( md * md < 1e-10 ) {
1160 Sys_Printf( "Cannot invert some matrix, some texcoords aren't extrapolated!" );
1164 m4x4_invert( solvematrix );
1166 scoeffs[0] = ast[0];
1167 scoeffs[1] = bst[0];
1168 scoeffs[2] = cst[0];
1170 m4x4_transform_vec4( solvematrix, scoeffs );
1171 tcoeffs[0] = ast[1];
1172 tcoeffs[1] = bst[1];
1173 tcoeffs[2] = cst[1];
1175 m4x4_transform_vec4( solvematrix, tcoeffs );
1177 ast_out[0] = scoeffs[0] * axyz_new[0] + scoeffs[1] * axyz_new[1] + scoeffs[2] * axyz_new[2] + scoeffs[3];
1178 ast_out[1] = tcoeffs[0] * axyz_new[0] + tcoeffs[1] * axyz_new[1] + tcoeffs[2] * axyz_new[2] + tcoeffs[3];
1179 bst_out[0] = scoeffs[0] * bxyz_new[0] + scoeffs[1] * bxyz_new[1] + scoeffs[2] * bxyz_new[2] + scoeffs[3];
1180 bst_out[1] = tcoeffs[0] * bxyz_new[0] + tcoeffs[1] * bxyz_new[1] + tcoeffs[2] * bxyz_new[2] + tcoeffs[3];
1181 cst_out[0] = scoeffs[0] * cxyz_new[0] + scoeffs[1] * cxyz_new[1] + scoeffs[2] * cxyz_new[2] + scoeffs[3];
1182 cst_out[1] = tcoeffs[0] * cxyz_new[0] + tcoeffs[1] * cxyz_new[1] + tcoeffs[2] * cxyz_new[2] + tcoeffs[3];
1187 amaze and confuse your enemies with wierd scaled maps!
1190 int ScaleBSPMain( int argc, char **argv ){
1198 float *old_xyzst = NULL;
1199 float spawn_ref = 0;
1204 Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref <value>] <value> <mapname>\n" );
1209 for ( i = 1; i < argc - 2; ++i )
1211 if ( !strcmp( argv[i], "-tex" ) ) {
1214 else if ( !strcmp( argv[i], "-spawn_ref" ) ) {
1215 spawn_ref = atof( argv[i + 1] );
1224 // if(argc-2 >= i) // always true
1225 scale[2] = scale[1] = scale[0] = atof( argv[ argc - 2 ] );
1226 if ( argc - 3 >= i ) {
1227 scale[1] = scale[0] = atof( argv[ argc - 3 ] );
1229 if ( argc - 4 >= i ) {
1230 scale[0] = atof( argv[ argc - 4 ] );
1233 uniform = ( ( scale[0] == scale[1] ) && ( scale[1] == scale[2] ) );
1235 if ( scale[0] == 0.0f || scale[1] == 0.0f || scale[2] == 0.0f ) {
1236 Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref <value>] <value> <mapname>\n" );
1237 Sys_Printf( "Non-zero scale value required.\n" );
1241 /* do some path mangling */
1242 strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
1243 StripExtension( source );
1244 DefaultExtension( source, ".bsp" );
1247 Sys_Printf( "Loading %s\n", source );
1248 LoadBSPFile( source );
1252 Sys_Printf( "--- ScaleBSP ---\n" );
1253 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1255 /* scale entity keys */
1256 for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
1259 GetVectorForKey( &entities[ i ], "origin", vec );
1260 if ( ( vec[ 0 ] || vec[ 1 ] || vec[ 2 ] ) ) {
1261 if ( !strncmp( ValueForKey( &entities[i], "classname" ), "info_player_", 12 ) ) {
1262 vec[2] += spawn_ref;
1267 if ( !strncmp( ValueForKey( &entities[i], "classname" ), "info_player_", 12 ) ) {
1268 vec[2] -= spawn_ref;
1270 sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
1271 SetKeyValue( &entities[ i ], "origin", str );
1274 a = FloatForKey( &entities[ i ], "angle" );
1275 if ( a == -1 || a == -2 ) { // z scale
1278 else if ( fabs( sin( DEG2RAD( a ) ) ) < 0.707 ) {
1285 /* scale door lip */
1286 f = FloatForKey( &entities[ i ], "lip" );
1289 sprintf( str, "%f", f );
1290 SetKeyValue( &entities[ i ], "lip", str );
1293 /* scale plat height */
1294 f = FloatForKey( &entities[ i ], "height" );
1297 sprintf( str, "%f", f );
1298 SetKeyValue( &entities[ i ], "height", str );
1301 // TODO maybe allow a definition file for entities to specify which values are scaled how?
1305 for ( i = 0; i < numBSPModels; i++ )
1307 bspModels[ i ].mins[0] *= scale[0];
1308 bspModels[ i ].mins[1] *= scale[1];
1309 bspModels[ i ].mins[2] *= scale[2];
1310 bspModels[ i ].maxs[0] *= scale[0];
1311 bspModels[ i ].maxs[1] *= scale[1];
1312 bspModels[ i ].maxs[2] *= scale[2];
1316 for ( i = 0; i < numBSPNodes; i++ )
1318 bspNodes[ i ].mins[0] *= scale[0];
1319 bspNodes[ i ].mins[1] *= scale[1];
1320 bspNodes[ i ].mins[2] *= scale[2];
1321 bspNodes[ i ].maxs[0] *= scale[0];
1322 bspNodes[ i ].maxs[1] *= scale[1];
1323 bspNodes[ i ].maxs[2] *= scale[2];
1327 for ( i = 0; i < numBSPLeafs; i++ )
1329 bspLeafs[ i ].mins[0] *= scale[0];
1330 bspLeafs[ i ].mins[1] *= scale[1];
1331 bspLeafs[ i ].mins[2] *= scale[2];
1332 bspLeafs[ i ].maxs[0] *= scale[0];
1333 bspLeafs[ i ].maxs[1] *= scale[1];
1334 bspLeafs[ i ].maxs[2] *= scale[2];
1338 Sys_Printf( "Using texture unlocking (and probably breaking texture alignment a lot)\n" );
1339 old_xyzst = safe_malloc( sizeof( *old_xyzst ) * numBSPDrawVerts * 5 );
1340 for ( i = 0; i < numBSPDrawVerts; i++ )
1342 old_xyzst[5 * i + 0] = bspDrawVerts[i].xyz[0];
1343 old_xyzst[5 * i + 1] = bspDrawVerts[i].xyz[1];
1344 old_xyzst[5 * i + 2] = bspDrawVerts[i].xyz[2];
1345 old_xyzst[5 * i + 3] = bspDrawVerts[i].st[0];
1346 old_xyzst[5 * i + 4] = bspDrawVerts[i].st[1];
1350 /* scale drawverts */
1351 for ( i = 0; i < numBSPDrawVerts; i++ )
1353 bspDrawVerts[i].xyz[0] *= scale[0];
1354 bspDrawVerts[i].xyz[1] *= scale[1];
1355 bspDrawVerts[i].xyz[2] *= scale[2];
1356 bspDrawVerts[i].normal[0] /= scale[0];
1357 bspDrawVerts[i].normal[1] /= scale[1];
1358 bspDrawVerts[i].normal[2] /= scale[2];
1359 VectorNormalize( bspDrawVerts[i].normal, bspDrawVerts[i].normal );
1363 for ( i = 0; i < numBSPDrawSurfaces; i++ )
1365 switch ( bspDrawSurfaces[i].surfaceType )
1369 if ( bspDrawSurfaces[i].numIndexes % 3 ) {
1370 Error( "Not a triangulation!" );
1372 for ( j = bspDrawSurfaces[i].firstIndex; j < bspDrawSurfaces[i].firstIndex + bspDrawSurfaces[i].numIndexes; j += 3 )
1374 int ia = bspDrawIndexes[j] + bspDrawSurfaces[i].firstVert, ib = bspDrawIndexes[j + 1] + bspDrawSurfaces[i].firstVert, ic = bspDrawIndexes[j + 2] + bspDrawSurfaces[i].firstVert;
1375 bspDrawVert_t *a = &bspDrawVerts[ia], *b = &bspDrawVerts[ib], *c = &bspDrawVerts[ic];
1376 float *oa = &old_xyzst[ia * 5], *ob = &old_xyzst[ib * 5], *oc = &old_xyzst[ic * 5];
1381 ExtrapolateTexcoords(
1396 for ( i = 0; i < numBSPPlanes; i++ )
1398 bspPlanes[ i ].dist *= scale[0];
1403 for ( i = 0; i < numBSPPlanes; i++ )
1405 bspPlanes[ i ].normal[0] /= scale[0];
1406 bspPlanes[ i ].normal[1] /= scale[1];
1407 bspPlanes[ i ].normal[2] /= scale[2];
1408 f = 1 / VectorLength( bspPlanes[i].normal );
1409 VectorScale( bspPlanes[i].normal, f, bspPlanes[i].normal );
1410 bspPlanes[ i ].dist *= f;
1414 /* scale gridsize */
1415 GetVectorForKey( &entities[ 0 ], "gridsize", vec );
1416 if ( ( vec[ 0 ] + vec[ 1 ] + vec[ 2 ] ) == 0.0f ) {
1417 VectorCopy( gridSize, vec );
1422 sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
1423 SetKeyValue( &entities[ 0 ], "gridsize", str );
1425 /* inject command line parameters */
1426 InjectCommandLine( argv, 0, argc - 1 );
1430 StripExtension( source );
1431 DefaultExtension( source, "_s.bsp" );
1432 Sys_Printf( "Writing %s\n", source );
1433 WriteBSPFile( source );
1435 /* return to sender */
1442 a stripped down ProcessModels
1444 void PseudoCompileBSP( qboolean need_tree ){
1446 char modelValue[10];
1455 SetDrawSurfacesBuffer();
1456 mapDrawSurfs = safe_malloc( sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS );
1457 memset( mapDrawSurfs, 0, sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS );
1458 numMapDrawSurfs = 0;
1462 for ( mapEntityNum = 0; mapEntityNum < numEntities; mapEntityNum++ )
1465 entity = &entities[ mapEntityNum ];
1466 if ( entity->brushes == NULL && entity->patches == NULL ) {
1470 if ( mapEntityNum != 0 ) {
1471 sprintf( modelValue, "*%d", models++ );
1472 SetKeyValue( entity, "model", modelValue );
1475 /* process the model */
1476 Sys_FPrintf( SYS_VRB, "############### model %i ###############\n", numBSPModels );
1479 entity->firstDrawSurf = numMapDrawSurfs;
1481 ClearMetaTriangles();
1482 PatchMapDrawSurfs( entity );
1484 if ( mapEntityNum == 0 && need_tree ) {
1485 faces = MakeStructuralBSPFaceList( entities[0].brushes );
1486 tree = FaceBSP( faces );
1487 node = tree->headnode;
1492 node->planenum = PLANENUM_LEAF;
1494 tree->headnode = node;
1497 /* a minimized ClipSidesIntoTree */
1498 for ( brush = entity->brushes; brush; brush = brush->next )
1500 /* walk the brush sides */
1501 for ( i = 0; i < brush->numsides; i++ )
1504 side = &brush->sides[ i ];
1505 if ( side->winding == NULL ) {
1509 if ( side->shaderInfo == NULL ) {
1512 /* save this winding as a visible surface */
1513 DrawSurfaceForSide( entity, brush, side, side->winding );
1518 ClassifyEntitySurfaces( entity );
1519 MakeEntityDecals( entity );
1520 MakeEntityMetaTriangles( entity );
1521 SmoothMetaTriangles();
1522 MergeMetaTriangles();
1524 FilterDrawsurfsIntoTree( entity, tree );
1526 FilterStructuralBrushesIntoTree( entity, tree );
1527 FilterDetailBrushesIntoTree( entity, tree );
1529 EmitBrushes( entity->brushes, &entity->firstBrush, &entity->numBrushes );
1530 EndModel( entity, node );
1532 EndBSPFile( qfalse );
1537 main argument processing function for bsp conversion
1540 int ConvertBSPMain( int argc, char **argv ){
1542 int ( *convertFunc )( char * );
1543 game_t *convertGame;
1545 qboolean map_allowed, force_bsp, force_map;
1549 convertFunc = ConvertBSPToASE;
1551 map_allowed = qfalse;
1557 Sys_Printf( "Usage: q3map -convert [-format <ase|obj|map_bp|map>] [-shadersasbitmap|-lightmapsastexcoord|-deluxemapsastexcoord] [-readbsp|-readmap [-meta|-patchmeta]] [-v] <mapname>\n" );
1561 /* process arguments */
1562 for ( i = 1; i < ( argc - 1 ); i++ )
1564 /* -format map|ase|... */
1565 if ( !strcmp( argv[ i ], "-format" ) ) {
1567 if ( !Q_stricmp( argv[ i ], "ase" ) ) {
1568 convertFunc = ConvertBSPToASE;
1569 map_allowed = qfalse;
1571 else if ( !Q_stricmp( argv[ i ], "obj" ) ) {
1572 convertFunc = ConvertBSPToOBJ;
1573 map_allowed = qfalse;
1575 else if ( !Q_stricmp( argv[ i ], "map_bp" ) ) {
1576 convertFunc = ConvertBSPToMap_BP;
1577 map_allowed = qtrue;
1579 else if ( !Q_stricmp( argv[ i ], "map" ) ) {
1580 convertFunc = ConvertBSPToMap;
1581 map_allowed = qtrue;
1585 convertGame = GetGame( argv[ i ] );
1586 map_allowed = qfalse;
1587 if ( convertGame == NULL ) {
1588 Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
1592 else if ( !strcmp( argv[ i ], "-ne" ) ) {
1593 normalEpsilon = atof( argv[ i + 1 ] );
1595 Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
1597 else if ( !strcmp( argv[ i ], "-de" ) ) {
1598 distanceEpsilon = atof( argv[ i + 1 ] );
1600 Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
1602 else if ( !strcmp( argv[ i ], "-shaderasbitmap" ) || !strcmp( argv[ i ], "-shadersasbitmap" ) ) {
1603 shadersAsBitmap = qtrue;
1605 else if ( !strcmp( argv[ i ], "-lightmapastexcoord" ) || !strcmp( argv[ i ], "-lightmapsastexcoord" ) ) {
1606 lightmapsAsTexcoord = qtrue;
1608 else if ( !strcmp( argv[ i ], "-deluxemapastexcoord" ) || !strcmp( argv[ i ], "-deluxemapsastexcoord" ) ) {
1609 lightmapsAsTexcoord = qtrue;
1612 else if ( !strcmp( argv[ i ], "-readbsp" ) ) {
1615 else if ( !strcmp( argv[ i ], "-readmap" ) ) {
1618 else if ( !strcmp( argv[ i ], "-meta" ) ) {
1621 else if ( !strcmp( argv[ i ], "-patchmeta" ) ) {
1629 /* clean up map name */
1630 strcpy( source, ExpandArg( argv[i] ) );
1631 ExtractFileExtension( source, ext );
1633 if ( !map_allowed && !force_map ) {
1637 if ( force_map || ( !force_bsp && !Q_stricmp( ext, "map" ) && map_allowed ) ) {
1638 if ( !map_allowed ) {
1639 Sys_Printf( "WARNING: the requested conversion should not be done from .map files. Compile a .bsp first.\n" );
1641 StripExtension( source );
1642 DefaultExtension( source, ".map" );
1643 Sys_Printf( "Loading %s\n", source );
1644 LoadMapFile( source, qfalse, convertGame == NULL );
1645 PseudoCompileBSP( convertGame != NULL );
1649 StripExtension( source );
1650 DefaultExtension( source, ".bsp" );
1651 Sys_Printf( "Loading %s\n", source );
1652 LoadBSPFile( source );
1656 /* bsp format convert? */
1657 if ( convertGame != NULL ) {
1658 /* set global game */
1662 StripExtension( source );
1663 DefaultExtension( source, "_c.bsp" );
1664 Sys_Printf( "Writing %s\n", source );
1665 WriteBSPFile( source );
1667 /* return to sender */
1671 /* normal convert */
1672 return convertFunc( source );
1682 int main( int argc, char **argv ){
1687 /* we want consistent 'randomness' */
1691 start = I_FloatTime();
1693 /* this was changed to emit version number over the network */
1694 printf( Q3MAP_VERSION "\n" );
1697 atexit( ExitQ3Map );
1699 /* read general options first */
1700 for ( i = 1; i < argc; i++ )
1703 if ( !strcmp( argv[ i ], "-connect" ) ) {
1706 Broadcast_Setup( argv[ i ] );
1711 else if ( !strcmp( argv[ i ], "-v" ) ) {
1719 else if ( !strcmp( argv[ i ], "-force" ) ) {
1724 /* patch subdivisions */
1725 else if ( !strcmp( argv[ i ], "-subdivisions" ) ) {
1728 patchSubdivisions = atoi( argv[ i ] );
1730 if ( patchSubdivisions <= 0 ) {
1731 patchSubdivisions = 1;
1736 else if ( !strcmp( argv[ i ], "-threads" ) ) {
1739 numthreads = atoi( argv[ i ] );
1744 /* init model library */
1746 PicoSetMallocFunc( safe_malloc );
1747 PicoSetFreeFunc( free );
1748 PicoSetPrintFunc( PicoPrintFunc );
1749 PicoSetLoadFileFunc( PicoLoadFileFunc );
1750 PicoSetFreeFileFunc( free );
1752 /* set number of threads */
1755 /* generate sinusoid jitter table */
1756 for ( i = 0; i < MAX_JITTERS; i++ )
1758 jitters[ i ] = sin( i * 139.54152147 );
1759 //% Sys_Printf( "Jitter %4d: %f\n", i, jitters[ i ] );
1762 /* we print out two versions, q3map's main version (since it evolves a bit out of GtkRadiant)
1763 and we put the GtkRadiant version to make it easy to track with what version of Radiant it was built with */
1765 Sys_Printf( "Q3Map - v1.0r (c) 1999 Id Software Inc.\n" );
1766 Sys_Printf( "Q3Map (ydnar) - v" Q3MAP_VERSION "\n" );
1767 Sys_Printf( "NetRadiant - v" RADIANT_VERSION " " __DATE__ " " __TIME__ "\n" );
1768 Sys_Printf( "%s\n", Q3MAP_MOTD );
1770 /* ydnar: new path initialization */
1771 InitPaths( &argc, argv );
1773 /* set game options */
1774 if ( !patchSubdivisions ) {
1775 patchSubdivisions = game->patchSubdivisions;
1778 /* check if we have enough options left to attempt something */
1780 Error( "Usage: %s [general options] [options] mapfile", argv[ 0 ] );
1784 if ( !strcmp( argv[ 1 ], "-fixaas" ) ) {
1785 r = FixAAS( argc - 1, argv + 1 );
1789 else if ( !strcmp( argv[ 1 ], "-analyze" ) ) {
1790 r = AnalyzeBSP( argc - 1, argv + 1 );
1794 else if ( !strcmp( argv[ 1 ], "-info" ) ) {
1795 r = BSPInfo( argc - 2, argv + 2 );
1799 else if ( !strcmp( argv[ 1 ], "-vis" ) ) {
1800 r = VisMain( argc - 1, argv + 1 );
1804 else if ( !strcmp( argv[ 1 ], "-light" ) ) {
1805 r = LightMain( argc - 1, argv + 1 );
1809 else if ( !strcmp( argv[ 1 ], "-vlight" ) ) {
1810 Sys_Printf( "WARNING: VLight is no longer supported, defaulting to -light -fast instead\n\n" );
1811 argv[ 1 ] = "-fast"; /* eek a hack */
1812 r = LightMain( argc, argv );
1815 /* ydnar: lightmap export */
1816 else if ( !strcmp( argv[ 1 ], "-export" ) ) {
1817 r = ExportLightmapsMain( argc - 1, argv + 1 );
1820 /* ydnar: lightmap import */
1821 else if ( !strcmp( argv[ 1 ], "-import" ) ) {
1822 r = ImportLightmapsMain( argc - 1, argv + 1 );
1825 /* ydnar: bsp scaling */
1826 else if ( !strcmp( argv[ 1 ], "-scale" ) ) {
1827 r = ScaleBSPMain( argc - 1, argv + 1 );
1830 /* ydnar: bsp conversion */
1831 else if ( !strcmp( argv[ 1 ], "-convert" ) ) {
1832 r = ConvertBSPMain( argc - 1, argv + 1 );
1836 else if ( !strcmp( argv[ 1 ], "-minimap" ) ) {
1837 r = MiniMapBSPMain( argc - 1, argv + 1 );
1840 /* ydnar: otherwise create a bsp */
1842 r = BSPMain( argc, argv );
1846 end = I_FloatTime();
1847 Sys_Printf( "%9.0f seconds elapsed\n", end - start );
1849 /* shut down connection */
1850 Broadcast_Shutdown();
1852 /* return any error code */