allow non-uniform -scale
[divverent/netradiant.git] / tools / quake3 / q3map2 / main.c
1 /* -------------------------------------------------------------------------------
2
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6 This file is part of GtkRadiant.
7
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.
12
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.
17
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
21
22 -------------------------------------------------------------------------------
23
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."
26
27 ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define MAIN_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41 /*
42 Random()
43 returns a pseudorandom number between 0 and 1
44 */
45
46 vec_t Random( void )
47 {
48         return (vec_t) rand() / RAND_MAX;
49 }
50
51
52
53 /*
54 ExitQ3Map()
55 cleanup routine
56 */
57
58 static void ExitQ3Map( void )
59 {
60         BSPFilesCleanup();
61         if( mapDrawSurfs != NULL )
62                 free( mapDrawSurfs );
63 }
64
65
66
67 /*
68 MD4BlockChecksum()
69 calculates an md4 checksum for a block of data
70 */
71
72 static int MD4BlockChecksum( void *buffer, int length )
73 {
74         return Com_BlockChecksum(buffer, length);
75 }
76
77
78
79 /*
80 FixAAS()
81 resets an aas checksum to match the given BSP
82 */
83
84 int FixAAS( int argc, char **argv )
85 {
86         int                     length, checksum;
87         void            *buffer;
88         FILE            *file;
89         char            aas[ 1024 ], **ext;
90         char            *exts[] =
91                                 {
92                                         ".aas",
93                                         "_b0.aas",
94                                         "_b1.aas",
95                                         NULL
96                                 };
97         
98         
99         /* arg checking */
100         if( argc < 2 )
101         {
102                 Sys_Printf( "Usage: q3map -fixaas [-v] <mapname>\n" );
103                 return 0;
104         }
105         
106         /* do some path mangling */
107         strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
108         StripExtension( source );
109         DefaultExtension( source, ".bsp" );
110         
111         /* note it */
112         Sys_Printf( "--- FixAAS ---\n" );
113         
114         /* load the bsp */
115         Sys_Printf( "Loading %s\n", source );
116         length = LoadFile( source, &buffer );
117         
118         /* create bsp checksum */
119         Sys_Printf( "Creating checksum...\n" );
120         checksum = LittleLong( MD4BlockChecksum( buffer, length ) );
121         
122         /* write checksum to aas */
123         ext = exts;
124         while( *ext )
125         {
126                 /* mangle name */
127                 strcpy( aas, source );
128                 StripExtension( aas );
129                 strcat( aas, *ext );
130                 Sys_Printf( "Trying %s\n", aas );
131                 ext++;
132                 
133                 /* fix it */
134                 file = fopen( aas, "r+b" );
135                 if( !file )
136                         continue;
137                 if( fwrite( &checksum, 4, 1, file ) != 1 )
138                         Error( "Error writing checksum to %s", aas );
139                 fclose( file );
140         }
141         
142         /* return to sender */
143         return 0;
144 }
145
146
147
148 /*
149 AnalyzeBSP() - ydnar
150 analyzes a Quake engine BSP file
151 */
152
153 typedef struct abspHeader_s
154 {
155         char                    ident[ 4 ];
156         int                             version;
157         
158         bspLump_t               lumps[ 1 ];     /* unknown size */
159 }
160 abspHeader_t;
161
162 typedef struct abspLumpTest_s
163 {
164         int                             radix, minCount;
165         char                    *name;
166 }
167 abspLumpTest_t;
168
169 int AnalyzeBSP( int argc, char **argv )
170 {
171         abspHeader_t                    *header;
172         int                                             size, i, version, offset, length, lumpInt, count;
173         char                                    ident[ 5 ];
174         void                                    *lump;
175         float                                   lumpFloat;
176         char                                    lumpString[ 1024 ], source[ 1024 ];
177         qboolean                                lumpSwap = qfalse;
178         abspLumpTest_t                  *lumpTest;
179         static abspLumpTest_t   lumpTests[] =
180                                                         {
181                                                                 { sizeof( bspPlane_t ),                 6,              "IBSP LUMP_PLANES" },
182                                                                 { sizeof( bspBrush_t ),                 1,              "IBSP LUMP_BRUSHES" },
183                                                                 { 8,                                                    6,              "IBSP LUMP_BRUSHSIDES" },
184                                                                 { sizeof( bspBrushSide_t ),             6,              "RBSP LUMP_BRUSHSIDES" },
185                                                                 { sizeof( bspModel_t ),                 1,              "IBSP LUMP_MODELS" },
186                                                                 { sizeof( bspNode_t ),                  2,              "IBSP LUMP_NODES" },
187                                                                 { sizeof( bspLeaf_t ),                  1,              "IBSP LUMP_LEAFS" },
188                                                                 { 104,                                                  3,              "IBSP LUMP_DRAWSURFS" },
189                                                                 { 44,                                                   3,              "IBSP LUMP_DRAWVERTS" },
190                                                                 { 4,                                                    6,              "IBSP LUMP_DRAWINDEXES" },
191                                                                 { 128 * 128 * 3,                                1,              "IBSP LUMP_LIGHTMAPS" },
192                                                                 { 256 * 256 * 3,                                1,              "IBSP LUMP_LIGHTMAPS (256 x 256)" },
193                                                                 { 512 * 512 * 3,                                1,              "IBSP LUMP_LIGHTMAPS (512 x 512)" },
194                                                                 { 0, 0, NULL }
195                                                         };
196         
197         
198         /* arg checking */
199         if( argc < 1 )
200         {
201                 Sys_Printf( "Usage: q3map -analyze [-lumpswap] [-v] <mapname>\n" );
202                 return 0;
203         }
204         
205         /* process arguments */
206         for( i = 1; i < (argc - 1); i++ )
207         {
208                 /* -format map|ase|... */
209                 if( !strcmp( argv[ i ],  "-lumpswap" ) )
210                 {
211                         Sys_Printf( "Swapped lump structs enabled\n" );
212                         lumpSwap = qtrue;
213                 }
214         }
215         
216         /* clean up map name */
217         strcpy( source, ExpandArg( argv[ i ] ) );
218         Sys_Printf( "Loading %s\n", source );
219         
220         /* load the file */
221         size = LoadFile( source, (void**) &header );
222         if( size == 0 || header == NULL )
223         {
224                 Sys_Printf( "Unable to load %s.\n", source );
225                 return -1;
226         }
227         
228         /* analyze ident/version */
229         memcpy( ident, header->ident, 4 );
230         ident[ 4 ] = '\0';
231         version = LittleLong( header->version );
232         
233         Sys_Printf( "Identity:      %s\n", ident );
234         Sys_Printf( "Version:       %d\n", version );
235         Sys_Printf( "---------------------------------------\n" );
236         
237         /* analyze each lump */
238         for( i = 0; i < 100; i++ )
239         {
240                 /* call of duty swapped lump pairs */
241                 if( lumpSwap )
242                 {
243                         offset = LittleLong( header->lumps[ i ].length );
244                         length = LittleLong( header->lumps[ i ].offset );
245                 }
246                 
247                 /* standard lump pairs */
248                 else
249                 {
250                         offset = LittleLong( header->lumps[ i ].offset );
251                         length = LittleLong( header->lumps[ i ].length );
252                 }
253                 
254                 /* extract data */
255                 lump = (byte*) header + offset;
256                 lumpInt = LittleLong( (int) *((int*) lump) );
257                 lumpFloat = LittleFloat( (float) *((float*) lump) );
258                 memcpy( lumpString, (char*) lump, (length < 1024 ? length : 1024) );
259                 lumpString[ 1024 ] = '\0';
260                 
261                 /* print basic lump info */
262                 Sys_Printf( "Lump:          %d\n", i );
263                 Sys_Printf( "Offset:        %d bytes\n", offset );
264                 Sys_Printf( "Length:        %d bytes\n", length );
265                 
266                 /* only operate on valid lumps */
267                 if( length > 0 )
268                 {
269                         /* print data in 4 formats */
270                         Sys_Printf( "As hex:        %08X\n", lumpInt );
271                         Sys_Printf( "As int:        %d\n", lumpInt );
272                         Sys_Printf( "As float:      %f\n", lumpFloat );
273                         Sys_Printf( "As string:     %s\n", lumpString );
274                         
275                         /* guess lump type */
276                         if( lumpString[ 0 ] == '{' && lumpString[ 2 ] == '"' )
277                                 Sys_Printf( "Type guess:    IBSP LUMP_ENTITIES\n" );
278                         else if( strstr( lumpString, "textures/" ) )
279                                 Sys_Printf( "Type guess:    IBSP LUMP_SHADERS\n" );
280                         else
281                         {
282                                 /* guess based on size/count */
283                                 for( lumpTest = lumpTests; lumpTest->radix > 0; lumpTest++ )
284                                 {
285                                         if( (length % lumpTest->radix) != 0 )
286                                                 continue;
287                                         count = length / lumpTest->radix;
288                                         if( count < lumpTest->minCount )
289                                                 continue;
290                                         Sys_Printf( "Type guess:    %s (%d x %d)\n", lumpTest->name, count, lumpTest->radix );
291                                 }
292                         }
293                 }
294                 
295                 Sys_Printf( "---------------------------------------\n" );
296                 
297                 /* end of file */
298                 if( offset + length >= size )
299                         break;
300         }
301         
302         /* last stats */
303         Sys_Printf( "Lump count:    %d\n", i + 1 );
304         Sys_Printf( "File size:     %d bytes\n", size );
305         
306         /* return to caller */
307         return 0;
308 }
309
310
311
312 /*
313 BSPInfo()
314 emits statistics about the bsp file
315 */
316
317 int BSPInfo( int count, char **fileNames )
318 {
319         int                     i;
320         char            source[ 1024 ], ext[ 64 ];
321         int                     size;
322         FILE            *f;
323         
324         
325         /* dummy check */
326         if( count < 1 )
327         {
328                 Sys_Printf( "No files to dump info for.\n");
329                 return -1;
330         }
331         
332         /* enable info mode */
333         infoMode = qtrue;
334         
335         /* walk file list */
336         for( i = 0; i < count; i++ )
337         {
338                 Sys_Printf( "---------------------------------\n" );
339                 
340                 /* mangle filename and get size */
341                 strcpy( source, fileNames[ i ] );
342                 ExtractFileExtension( source, ext );
343                 if( !Q_stricmp( ext, "map" ) )
344                         StripExtension( source );
345                 DefaultExtension( source, ".bsp" );
346                 f = fopen( source, "rb" );
347                 if( f )
348                 {
349                         size = Q_filelength (f);
350                         fclose( f );
351                 }
352                 else
353                         size = 0;
354                 
355                 /* load the bsp file and print lump sizes */
356                 Sys_Printf( "%s\n", source );
357                 LoadBSPFile( source );          
358                 PrintBSPFileSizes();
359                 
360                 /* print sizes */
361                 Sys_Printf( "\n" );
362                 Sys_Printf( "          total         %9d\n", size );
363                 Sys_Printf( "                        %9d KB\n", size / 1024 );
364                 Sys_Printf( "                        %9d MB\n", size / (1024 * 1024) );
365                 
366                 Sys_Printf( "---------------------------------\n" );
367         }
368         
369         /* return count */
370         return i;
371 }
372
373
374
375 /*
376 ScaleBSPMain()
377 amaze and confuse your enemies with wierd scaled maps!
378 */
379
380 int ScaleBSPMain( int argc, char **argv )
381 {
382         int                     i;
383         float           f, a;
384         vec3_t scale;
385         vec3_t          vec;
386         char            str[ 1024 ];
387         int uniform;
388         
389         
390         /* arg checking */
391         if( argc < 2 )
392         {
393                 Sys_Printf( "Usage: q3map -scale <value> [-v] <mapname>\n" );
394                 return 0;
395         }
396         
397         /* get scale */
398         scale[2] = scale[1] = scale[0] = atof( argv[ argc - 2 ] );
399         if(argc >= 3)
400                 scale[1] = scale[0] = atof( argv[ argc - 3 ] );
401         if(argc >= 4)
402                 scale[0] = atof( argv[ argc - 4 ] );
403         
404         uniform = ((scale[0] == scale[1]) && (scale[1] == scale[2]));
405
406         if( scale[0] == 0.0f || scale[1] == 0.0f || scale[2] == 0.0f )
407         {
408                 Sys_Printf( "Usage: q3map -scale <value> <mapname>\n" );
409                 Sys_Printf( "Non-zero scale value required.\n" );
410                 return 0;
411         }
412         
413         /* do some path mangling */
414         strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
415         StripExtension( source );
416         DefaultExtension( source, ".bsp" );
417         
418         /* load the bsp */
419         Sys_Printf( "Loading %s\n", source );
420         LoadBSPFile( source );
421         ParseEntities();
422         
423         /* note it */
424         Sys_Printf( "--- ScaleBSP ---\n" );
425         Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
426         
427         /* scale entity keys */
428         for( i = 0; i < numBSPEntities && i < numEntities; i++ )
429         {
430                 /* scale origin */
431                 GetVectorForKey( &entities[ i ], "origin", vec );
432                 if( (vec[ 0 ] || vec[ 1 ] || vec[ 2 ]) )
433                 {
434                         vec[0] *= scale[0];
435                         vec[1] *= scale[1];
436                         vec[2] *= scale[2];
437                         sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
438                         SetKeyValue( &entities[ i ], "origin", str );
439                 }
440                 
441                 /* scale door lip */
442                 f = FloatForKey( &entities[ i ], "lip" );
443                 a = FloatForKey( &entities[ i ], "angle" );
444                 if( f )
445                 {
446                         if(a == -1 || a == -2) // z scale
447                                 f *= scale[2];
448                         else if(fabs(sin(DEG2RAD(a))) < 0.707)
449                                 f *= scale[0];
450                         else
451                                 f *= scale[1];
452                         sprintf( str, "%f", f );
453                         SetKeyValue( &entities[ i ], "lip", str );
454                 }
455         }
456         
457         /* scale models */
458         for( i = 0; i < numBSPModels; i++ )
459         {
460                 bspModels[ i ].mins[0] *= scale[0];
461                 bspModels[ i ].mins[1] *= scale[1];
462                 bspModels[ i ].mins[2] *= scale[2];
463                 bspModels[ i ].maxs[0] *= scale[0];
464                 bspModels[ i ].maxs[1] *= scale[1];
465                 bspModels[ i ].maxs[2] *= scale[2];
466         }
467         
468         /* scale nodes */
469         for( i = 0; i < numBSPNodes; i++ )
470         {
471                 bspNodes[ i ].mins[0] *= scale[0];
472                 bspNodes[ i ].mins[1] *= scale[1];
473                 bspNodes[ i ].mins[2] *= scale[2];
474                 bspNodes[ i ].maxs[0] *= scale[0];
475                 bspNodes[ i ].maxs[1] *= scale[1];
476                 bspNodes[ i ].maxs[2] *= scale[2];
477         }
478         
479         /* scale leafs */
480         for( i = 0; i < numBSPLeafs; i++ )
481         {
482                 bspLeafs[ i ].mins[0] *= scale[0];
483                 bspLeafs[ i ].mins[1] *= scale[1];
484                 bspLeafs[ i ].mins[2] *= scale[2];
485                 bspLeafs[ i ].maxs[0] *= scale[0];
486                 bspLeafs[ i ].maxs[1] *= scale[1];
487                 bspLeafs[ i ].maxs[2] *= scale[2];
488         }
489         
490         /* scale drawverts */
491         for( i = 0; i < numBSPDrawVerts; i++ )
492         {
493                 bspDrawVerts[i].xyz[0] *= scale[0];
494                 bspDrawVerts[i].xyz[1] *= scale[1];
495                 bspDrawVerts[i].xyz[2] *= scale[2];
496                 bspDrawVerts[i].normal[0] /= scale[0];
497                 bspDrawVerts[i].normal[1] /= scale[1];
498                 bspDrawVerts[i].normal[2] /= scale[2];
499                 VectorNormalize(bspDrawVerts[i].normal, bspDrawVerts[i].normal);
500         }
501         
502         /* scale planes */
503         if(uniform)
504         {
505                 for( i = 0; i < numBSPPlanes; i++ )
506                 {
507                         bspPlanes[ i ].dist *= scale[0];
508                 }
509         }
510         else
511         {
512                 for( i = 0; i < numBSPPlanes; i++ )
513                 {
514                         bspPlanes[ i ].normal[0] /= scale[0];
515                         bspPlanes[ i ].normal[1] /= scale[1];
516                         bspPlanes[ i ].normal[2] /= scale[2];
517                         f = 1/VectorLength(bspPlanes[i].normal);
518                         VectorScale(bspPlanes[i].normal, f, bspPlanes[i].normal);
519                         bspPlanes[ i ].dist *= f;
520                 }
521         }
522         
523         /* scale gridsize */
524         GetVectorForKey( &entities[ 0 ], "gridsize", vec );
525         if( (vec[ 0 ] + vec[ 1 ] + vec[ 2 ]) == 0.0f )
526                 VectorCopy( gridSize, vec );
527         vec[0] *= scale[0];
528         vec[1] *= scale[1];
529         vec[2] *= scale[2];
530         sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
531         SetKeyValue( &entities[ 0 ], "gridsize", str );
532
533         /* inject command line parameters */
534         InjectCommandLine(argv, 0, argc - 1);
535         
536         /* write the bsp */
537         UnparseEntities();
538         StripExtension( source );
539         DefaultExtension( source, "_s.bsp" );
540         Sys_Printf( "Writing %s\n", source );
541         WriteBSPFile( source );
542         
543         /* return to sender */
544         return 0;
545 }
546
547
548
549 /*
550 ConvertBSPMain()
551 main argument processing function for bsp conversion
552 */
553
554 int ConvertBSPMain( int argc, char **argv )
555 {
556         int             i;
557         int             (*convertFunc)( char * );
558         game_t  *convertGame;
559         
560         
561         /* set default */
562         convertFunc = ConvertBSPToASE;
563         convertGame = NULL;
564         
565         /* arg checking */
566         if( argc < 1 )
567         {
568                 Sys_Printf( "Usage: q3map -scale <value> [-v] <mapname>\n" );
569                 return 0;
570         }
571         
572         /* process arguments */
573         for( i = 1; i < (argc - 1); i++ )
574         {
575                 /* -format map|ase|... */
576                 if( !strcmp( argv[ i ],  "-format" ) )
577                 {
578                         i++;
579                         if( !Q_stricmp( argv[ i ], "ase" ) )
580                                 convertFunc = ConvertBSPToASE;
581                         else if( !Q_stricmp( argv[ i ], "map" ) )
582                                 convertFunc = ConvertBSPToMap;
583                         else
584                         {
585                                 convertGame = GetGame( argv[ i ] );
586                                 if( convertGame == NULL )
587                                         Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
588                         }
589                 }
590                 else if( !strcmp( argv[ i ],  "-ne" ) )
591                 {
592                         normalEpsilon = atof( argv[ i + 1 ] );
593                         i++;
594                         Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
595                 }
596                 else if( !strcmp( argv[ i ],  "-de" ) )
597                 {
598                         distanceEpsilon = atof( argv[ i + 1 ] );
599                         i++;
600                         Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
601                 }
602                 else if( !strcmp( argv[ i ],  "-shadersasbitmap" ) )
603                         shadersAsBitmap = qtrue;
604         }
605         
606         /* clean up map name */
607         strcpy( source, ExpandArg( argv[ i ] ) );
608         StripExtension( source );
609         DefaultExtension( source, ".bsp" );
610         
611         LoadShaderInfo();
612         
613         Sys_Printf( "Loading %s\n", source );
614         
615         /* ydnar: load surface file */
616         //%     LoadSurfaceExtraFile( source );
617         
618         LoadBSPFile( source );
619         
620         /* parse bsp entities */
621         ParseEntities();
622         
623         /* bsp format convert? */
624         if( convertGame != NULL )
625         {
626                 /* set global game */
627                 game = convertGame;
628                 
629                 /* write bsp */
630                 StripExtension( source );
631                 DefaultExtension( source, "_c.bsp" );
632                 Sys_Printf( "Writing %s\n", source );
633                 WriteBSPFile( source );
634                 
635                 /* return to sender */
636                 return 0;
637         }
638         
639         /* normal convert */
640         return convertFunc( source );
641 }
642
643
644
645 /*
646 main()
647 q3map mojo...
648 */
649
650 int main( int argc, char **argv )
651 {
652         int             i, r;
653         double  start, end;
654         
655         
656         /* we want consistent 'randomness' */
657         srand( 0 );
658         
659         /* start timer */
660         start = I_FloatTime();
661
662         /* this was changed to emit version number over the network */
663         printf( Q3MAP_VERSION "\n" );
664         
665         /* set exit call */
666         atexit( ExitQ3Map );
667         
668         /* read general options first */
669         for( i = 1; i < argc; i++ )
670         {
671                 /* -connect */
672                 if( !strcmp( argv[ i ], "-connect" ) )
673                 {
674                         argv[ i ] = NULL;
675                         i++;
676                         Broadcast_Setup( argv[ i ] );
677                         argv[ i ] = NULL;
678                 }
679                 
680                 /* verbose */
681                 else if( !strcmp( argv[ i ], "-v" ) )
682                 {
683                         verbose = qtrue;
684                         argv[ i ] = NULL;
685                 }
686                 
687                 /* force */
688                 else if( !strcmp( argv[ i ], "-force" ) )
689                 {
690                         force = qtrue;
691                         argv[ i ] = NULL;
692                 }
693                 
694                 /* patch subdivisions */
695                 else if( !strcmp( argv[ i ], "-subdivisions" ) )
696                 {
697                         argv[ i ] = NULL;
698                         i++;
699                         patchSubdivisions = atoi( argv[ i ] );
700                         argv[ i ] = NULL;
701                         if( patchSubdivisions <= 0 )
702                                 patchSubdivisions = 1;
703                 }
704                 
705                 /* threads */
706                 else if( !strcmp( argv[ i ], "-threads" ) )
707                 {
708                         argv[ i ] = NULL;
709                         i++;
710                         numthreads = atoi( argv[ i ] );
711                         argv[ i ] = NULL;
712                 }
713         }
714         
715         /* init model library */
716         PicoInit();
717         PicoSetMallocFunc( safe_malloc );
718         PicoSetFreeFunc( free );
719         PicoSetPrintFunc( PicoPrintFunc );
720         PicoSetLoadFileFunc( PicoLoadFileFunc );
721         PicoSetFreeFileFunc( free );
722         
723         /* set number of threads */
724         ThreadSetDefault();
725         
726         /* generate sinusoid jitter table */
727         for( i = 0; i < MAX_JITTERS; i++ )
728         {
729                 jitters[ i ] = sin( i * 139.54152147 );
730                 //%     Sys_Printf( "Jitter %4d: %f\n", i, jitters[ i ] );
731         }
732         
733         /* we print out two versions, q3map's main version (since it evolves a bit out of GtkRadiant)
734            and we put the GtkRadiant version to make it easy to track with what version of Radiant it was built with */
735         
736         Sys_Printf( "Q3Map         - v1.0r (c) 1999 Id Software Inc.\n" );
737         Sys_Printf( "Q3Map (ydnar) - v" Q3MAP_VERSION "\n" );
738         Sys_Printf( "NetRadiant    - v" RADIANT_VERSION " " __DATE__ " " __TIME__ "\n" );
739         Sys_Printf( "%s\n", Q3MAP_MOTD );
740         
741         /* ydnar: new path initialization */
742         InitPaths( &argc, argv );
743         
744         /* check if we have enough options left to attempt something */
745         if( argc < 2 )
746                 Error( "Usage: %s [general options] [options] mapfile", argv[ 0 ] );
747         
748         /* fixaas */
749         if( !strcmp( argv[ 1 ], "-fixaas" ) )
750                 r = FixAAS( argc - 1, argv + 1 );
751         
752         /* analyze */
753         else if( !strcmp( argv[ 1 ], "-analyze" ) )
754                 r = AnalyzeBSP( argc - 1, argv + 1 );
755         
756         /* info */
757         else if( !strcmp( argv[ 1 ], "-info" ) )
758                 r = BSPInfo( argc - 2, argv + 2 );
759         
760         /* vis */
761         else if( !strcmp( argv[ 1 ], "-vis" ) )
762                 r = VisMain( argc - 1, argv + 1 );
763         
764         /* light */
765         else if( !strcmp( argv[ 1 ], "-light" ) )
766                 r = LightMain( argc - 1, argv + 1 );
767         
768         /* vlight */
769         else if( !strcmp( argv[ 1 ], "-vlight" ) )
770         {
771                 Sys_Printf( "WARNING: VLight is no longer supported, defaulting to -light -fast instead\n\n" );
772                 argv[ 1 ] = "-fast";    /* eek a hack */
773                 r = LightMain( argc, argv );
774         }
775         
776         /* ydnar: lightmap export */
777         else if( !strcmp( argv[ 1 ], "-export" ) )
778                 r = ExportLightmapsMain( argc - 1, argv + 1 );
779         
780         /* ydnar: lightmap import */
781         else if( !strcmp( argv[ 1 ], "-import" ) )
782                 r = ImportLightmapsMain( argc - 1, argv + 1 );
783         
784         /* ydnar: bsp scaling */
785         else if( !strcmp( argv[ 1 ], "-scale" ) )
786                 r = ScaleBSPMain( argc - 1, argv + 1 );
787         
788         /* ydnar: bsp conversion */
789         else if( !strcmp( argv[ 1 ], "-convert" ) )
790                 r = ConvertBSPMain( argc - 1, argv + 1 );
791         
792         /* ydnar: otherwise create a bsp */
793         else
794                 r = BSPMain( argc, argv );
795         
796         /* emit time */
797         end = I_FloatTime();
798         Sys_Printf( "%9.0f seconds elapsed\n", end - start );
799         
800         /* shut down connection */
801         Broadcast_Shutdown();
802         
803         /* return any error code */
804         return r;
805 }