6c3b165cb6579d2cbbd5ccd08d8361cd90cb1c1a
[xonotic/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         return (vec_t) rand() / RAND_MAX;
48 }
49
50
51 char *Q_strncpyz( char *dst, const char *src, size_t len ) {
52         if ( len == 0 ) {
53                 abort();
54         }
55
56         strncpy( dst, src, len );
57         dst[ len - 1 ] = '\0';
58         return dst;
59 }
60
61
62 char *Q_strcat( char *dst, size_t dlen, const char *src ) {
63         size_t n = strlen( dst  );
64
65         if ( n > dlen ) {
66                 abort(); /* buffer overflow */
67         }
68
69         return Q_strncpyz( dst + n, src, dlen - n );
70 }
71
72
73 char *Q_strncat( char *dst, size_t dlen, const char *src, size_t slen ) {
74         size_t n = strlen( dst );
75
76         if ( n > dlen ) {
77                 abort(); /* buffer overflow */
78         }
79
80         return Q_strncpyz( dst + n, src, MIN( slen, dlen - n ) );
81 }
82
83 /*
84    ExitQ3Map()
85    cleanup routine
86  */
87
88 static void ExitQ3Map( void ){
89         BSPFilesCleanup();
90         if ( mapDrawSurfs != NULL ) {
91                 free( mapDrawSurfs );
92         }
93 }
94
95 /*
96    MD4BlockChecksum()
97    calculates an md4 checksum for a block of data
98  */
99
100 static int MD4BlockChecksum( void *buffer, int length ){
101         return Com_BlockChecksum( buffer, length );
102 }
103
104 /*
105    FixAAS()
106    resets an aas checksum to match the given BSP
107  */
108
109 int FixAAS( int argc, char **argv ){
110         int length, checksum;
111         void        *buffer;
112         FILE        *file;
113         char aas[ 1024 ], **ext;
114         char        *exts[] =
115         {
116                 ".aas",
117                 "_b0.aas",
118                 "_b1.aas",
119                 NULL
120         };
121
122
123         /* arg checking */
124         if ( argc < 2 ) {
125                 Sys_Printf( "Usage: q3map -fixaas [-v] <mapname>\n" );
126                 return 0;
127         }
128
129         /* do some path mangling */
130         strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
131         StripExtension( source );
132         DefaultExtension( source, ".bsp" );
133
134         /* note it */
135         Sys_Printf( "--- FixAAS ---\n" );
136
137         /* load the bsp */
138         Sys_Printf( "Loading %s\n", source );
139         length = LoadFile( source, &buffer );
140
141         /* create bsp checksum */
142         Sys_Printf( "Creating checksum...\n" );
143         checksum = LittleLong( MD4BlockChecksum( buffer, length ) );
144
145         /* write checksum to aas */
146         ext = exts;
147         while ( *ext )
148         {
149                 /* mangle name */
150                 strcpy( aas, source );
151                 StripExtension( aas );
152                 strcat( aas, *ext );
153                 Sys_Printf( "Trying %s\n", aas );
154                 ext++;
155
156                 /* fix it */
157                 file = fopen( aas, "r+b" );
158                 if ( !file ) {
159                         continue;
160                 }
161                 if ( fwrite( &checksum, 4, 1, file ) != 1 ) {
162                         Error( "Error writing checksum to %s", aas );
163                 }
164                 fclose( file );
165         }
166
167         /* return to sender */
168         return 0;
169 }
170
171 struct HelpOption
172 {
173         const char* name;
174         const char* description;
175 };
176
177 void HelpOptions(const char* group_name, int indentation, int width, struct HelpOption* options, int count)
178 {
179         indentation *= 2;
180         char* indent = malloc(indentation+1);
181         memset(indent, ' ', indentation);
182         indent[indentation] = 0;
183         printf("%s%s:\n", indent, group_name);
184         indentation += 2;
185         indent = realloc(indent, indentation+1);
186         memset(indent, ' ', indentation);
187         indent[indentation] = 0;
188
189         int i;
190         for ( i = 0; i < count; i++ )
191         {
192                 int printed = printf("%s%-24s  ", indent, options[i].name);
193                 int descsz = strlen(options[i].description);
194                 int j = 0;
195                 while ( j < descsz && descsz-j > width - printed )
196                 {
197                         if ( j != 0 )
198                                 printf("%s%26c",indent,' ');
199                         int fragment = width - printed;
200                         while ( fragment > 0 && options[i].description[j+fragment-1] != ' ')
201                                         fragment--;
202                         j += fwrite(options[i].description+j, sizeof(char), fragment, stdout);
203                         putchar('\n');
204                         printed = indentation+26;
205                 }
206                 if ( j == 0 )
207                 {
208                         printf("%s\n",options[i].description+j);
209                 }
210                 else if ( j < descsz )
211                 {
212                         printf("%s%26c%s\n",indent,' ',options[i].description+j);
213                 }
214         }
215
216         putchar('\n');
217
218         free(indent);
219 }
220
221 void HelpBsp()
222 {
223         struct HelpOption bsp[] = {
224                 {"-bsp <filename.map>", "Switch that enters this stage"},
225                 {"-altsplit", "Alternate BSP tree splitting weights (should give more fps)"},
226                 {"-celshader <shadername>", "Sets a global cel shader name"},
227                 {"-custinfoparms", "Read scripts/custinfoparms.txt"},
228                 {"-debuginset", "Push all triangle vertexes towards the triangle center"},
229                 {"-debugportals", "Make BSP portals visible in the map"},
230                 {"-debugsurfaces", "Color the vertexes according to the index of the surface"},
231                 {"-deep", "Use detail brushes in the BSP tree, but at lowest priority (should give more fps)"},
232                 {"-de <F>", "Distance epsilon for plane snapping etc."},
233                 {"-fakemap", "Write fakemap.map containing all world brushes"},
234                 {"-flares", "Turn on support for flares (TEST?)"},
235                 {"-flat", "Enable flat shading (good for combining with -celshader)"},
236                 {"-fulldetail", "Treat detail brushes as structural ones"},
237                 {"-leaktest", "Abort if a leak was found"},
238                 {"-meta", "Combine adjacent triangles of the same texture to surfaces (ALWAYS USE THIS)"},
239                 {"-minsamplesize <N>", "Sets minimum lightmap resolution in luxels/qu"},
240                 {"-mi <N>", "Sets the maximum number of indexes per surface"},
241                 {"-mv <N>", "Sets the maximum number of vertices of a lightmapped surface"},
242                 {"-ne <F>", "Normal epsilon for plane snapping etc."},
243                 {"-nocurves", "Turn off support for patches"},
244                 {"-nodetail", "Leave out detail brushes"},
245                 {"-noflares", "Turn off support for flares"},
246                 {"-nofog", "Turn off support for fog volumes"},
247                 {"-nohint", "Turn off support for hint brushes"},
248                 {"-nosubdivide", "Turn off support for `q3map_tessSize` (breaks water vertex deforms)"},
249                 {"-notjunc", "Do not fix T-junctions (causes cracks between triangles, do not use)"},
250                 {"-nowater", "Turn off support for water, slime or lava (Stef, this is for you)"},
251                 {"-np <A>", "Force all surfaces to be nonplanar with a given shade angle"},
252                 {"-onlyents", "Only update entities in the BSP"},
253                 {"-patchmeta", "Turn patches into triangle meshes for display"},
254                 {"-rename", "Append â€œbspâ€\9d suffix to miscmodel shaders (needed for SoF2)"},
255                 {"-samplesize <N>", "Sets default lightmap resolution in luxels/qu"},
256                 {"-skyfix", "Turn sky box into six surfaces to work around ATI problems"},
257                 {"-snap <N>", "Snap brush bevel planes to the given number of units"},
258                 {"-tempname <filename.map>", "Read the MAP file from the given file name"},
259                 {"-texrange <N>", "Limit per-surface texture range to the given number of units, and subdivide surfaces like with `q3map_tessSize` if this is not met"},
260                 {"-tmpout", "Write the BSP file to /tmp"},
261                 {"-verboseentities", "Enable `-v` only for map entities, not for the world"},
262         };
263         HelpOptions("BSP Stage", 0, 80, bsp, sizeof(bsp)/sizeof(struct HelpOption));
264 }
265 void HelpVis()
266 {
267         struct HelpOption vis[] = {
268                 {"-vis <filename.map>", "Switch that enters this stage"},
269                 {"-fast", "Very fast and crude vis calculation"},
270                 {"-mergeportals", "The less crude half of `-merge`, makes vis sometimes much faster but doesn't hurt fps usually"},
271                 {"-merge", "Faster but still okay vis calculation"},
272                 {"-nopassage", "Just use PortalFlow vis (usually less fps)"},
273                 {"-nosort", "Do not sort the portals before calculating vis (usually slower)"},
274                 {"-passageOnly", "Just use PassageFlow vis (usually less fps)"},
275                 {"-saveprt", "Keep the PRT file after running vis (so you can run vis again)"},
276                 {"-tmpin", "Use /tmp folder for input"},
277                 {"-tmpout", "Use /tmp folder for output"},
278         };
279         HelpOptions("VIS Stage", 0, 80, vis, sizeof(vis)/sizeof(struct HelpOption));
280 }
281 void HelpLight()
282 {
283         struct HelpOption light[] = {
284                 {"-light <filename.map>", "Switch that enters this stage"},
285                 {"-vlight <filename.map>", "Deprecated alias for `-light -fast` ... filename.map"},
286                 {"-approx <N>", "Vertex light approximation tolerance (never use in conjunction with deluxemapping)"},
287                 {"-areascale <F, `-area` F>", "Scaling factor for area lights (surfacelight)"},
288                 {"-border", "Add a red border to lightmaps for debugging"},
289                 {"-bouncegrid", "Also compute radiosity on the light grid"},
290                 {"-bounceonly", "Only compute radiosity"},
291                 {"-bouncescale <F>", "Scaling factor for radiosity"},
292                 {"-bounce <N>", "Number of bounces for radiosity"},
293                 {"-cheapgrid", "Use `-cheap` style lighting for radiosity"},
294                 {"-cheap", "Abort vertex light calculations when white is reached"},
295                 {"-compensate <F>", "Lightmap compensate (darkening factor applied after everything else)"},
296                 {"-cpma", "CPMA vertex lighting mode"},
297                 {"-custinfoparms", "Read scripts/custinfoparms.txt"},
298                 {"-dark", "Darken lightmap seams"},
299                 {"-debugaxis", "Color the lightmaps according to the lightmap axis"},
300                 {"-debugcluster", "Color the lightmaps according to the index of the cluster"},
301                 {"-debugdeluxe", "Show deluxemaps on the lightmap"},
302                 {"-debugnormals", "Color the lightmaps according to the direction of the surface normal"},
303                 {"-debugorigin", "Color the lightmaps according to the origin of the luxels"},
304                 {"-debugsurfaces, -debugsurface", "Color the lightmaps according to the index of the surface"},
305                 {"-debugunused", "This option does nothing"},
306                 {"-debug", "Mark the lightmaps according to the cluster: unmapped clusters get yellow, occluded ones get pink, flooded ones get blue overlay color, otherwise red"},
307                 {"-deluxemode 0", "Use modelspace deluxemaps (DarkPlaces)"},
308                 {"-deluxemode 1", "Use tangentspace deluxemaps"},
309                 {"-deluxe, -deluxemap", "Enable deluxemapping (light direction maps)"},
310                 {"-dirtdebug, -debugdirt", "Store the dirtmaps as lightmaps for debugging"},
311                 {"-dirtdepth", "Dirtmapping depth"},
312                 {"-dirtgain", "Dirtmapping exponent"},
313                 {"-dirtmode 0", "Ordered direction dirtmapping"},
314                 {"-dirtmode 1", "Randomized direction dirtmapping"},
315                 {"-dirtscale", "Dirtmapping scaling factor"},
316                 {"-dirty", "Enable dirtmapping"},
317                 {"-dump", "Dump radiosity from `-bounce` into numbered MAP file prefabs"},
318                 {"-export", "Export lightmaps when compile finished (like `-export` mode)"},
319                 {"-exposure <F>", "Lightmap exposure to better support overbright spots"},
320                 {"-external", "Force external lightmaps even if at size of internal lightmaps"},
321                 {"-extravisnudge", "Broken feature to nudge the luxel origin to a better vis cluster"},
322                 {"-extrawide", "Deprecated alias for `-super 2 -filter`"},
323                 {"-extra", "Deprecated alias for `-super 2`"},
324                 {"-fastbounce", "Use `-fast` style lighting for radiosity"},
325                 {"-faster", "Use a faster falloff curve for lighting; also implies `-fast`"},
326                 {"-fastgrid", "Use `-fast` style lighting for the light grid"},
327                 {"-fast", "Ignore tiny light contributions"},
328                 {"-filter", "Lightmap filtering"},
329                 {"-floodlight", "Enable floodlight (zero-effort somewhat decent lighting)"},
330                 {"-gamma <F>", "Lightmap gamma"},
331                 {"-gridambientscale <F>", "Scaling factor for the light grid ambient components only"},
332                 {"-gridscale <F>", "Scaling factor for the light grid only"},
333                 {"-keeplights", "Keep light entities in the BSP file after compile"},
334                 {"-lightmapdir <directory>", "Directory to store external lightmaps (default: same as map name without extension)"},
335                 {"-lightmapsize <N>", "Size of lightmaps to generate (must be a power of two)"},
336                 {"-lomem", "Low memory but slower lighting mode"},
337                 {"-lowquality", "Low quality floodlight (appears to currently break floodlight)"},
338                 {"-minsamplesize <N>", "Sets minimum lightmap resolution in luxels/qu"},
339                 {"-nocollapse", "Do not collapse identical lightmaps"},
340                 {"-nodeluxe, -nodeluxemap", "Disable deluxemapping"},
341                 {"-nogrid", "Disable grid light calculation (makes all entities fullbright)"},
342                 {"-nolightmapsearch", "Do not optimize lightmap packing for GPU memory usage (as doing so costs fps)"},
343                 {"-normalmap", "Color the lightmaps according to the direction of the surface normal (TODO is this identical to `-debugnormals`?)"},
344                 {"-nostyle, -nostyles", "Disable support for light styles"},
345                 {"-nosurf", "Disable tracing against surfaces (only uses BSP nodes then)"},
346                 {"-notrace", "Disable shadow occlusion"},
347                 {"-novertex", "Disable vertex lighting"},
348                 {"-patchshadows", "Cast shadows from patches"},
349                 {"-pointscale <F, `-point` F>", "Scaling factor for point lights (light entities)"},
350                 {"-q3", "Use nonlinear falloff curve by default (like Q3A)"},
351                 {"-samplescale <F>", "Scales all lightmap resolutions"},
352                 {"-samplesize <N>", "Sets default lightmap resolution in luxels/qu"},
353                 {"-samples <N>", "Adaptive supersampling quality"},
354                 {"-scale <F>", "Scaling factor for all light types"},
355                 {"-shadeangle <A>", "Angle for phong shading"},
356                 {"-shade", "Enable phong shading at default shade angle"},
357                 {"-skyscale <F, `-sky` F>", "Scaling factor for sky and sun light"},
358                 {"-smooth", "Deprecated alias for `-samples 2`"},
359                 {"-style, -styles", "Enable support for light styles"},
360                 {"-sunonly", "Only compute sun light"},
361                 {"-super <N, `-supersample` N>", "Ordered grid supersampling quality"},
362                 {"-thresh <F>", "Triangle subdivision threshold"},
363                 {"-trianglecheck", "Broken check that should ensure luxels apply to the right triangle"},
364                 {"-trisoup", "Convert brush faces to triangle soup"},
365                 {"-wolf", "Use linear falloff curve by default (like W:ET)"},
366         };
367
368         HelpOptions("Light Stage", 0, 80, light, sizeof(light)/sizeof(struct HelpOption));
369 }
370
371 void HelpAnalize()
372 {
373         struct HelpOption analize[] = {
374                 {"-analyze <filename.bsp>", "Switch that enters this mode"},
375                 {"-lumpswap", "Swap byte order in the lumps"},
376         };
377
378         HelpOptions("Analyzing BSP-like file structure", 0, 80, analize, sizeof(analize)/sizeof(struct HelpOption));
379 }
380 void HelpScale()
381 {
382         struct HelpOption scale[] = {
383                 {"-scale <S filename.bsp>", "Scale uniformly"},
384                 {"-scale <SX SY SZ filename.bsp>", "Scale non-uniformly"},
385                 {"-scale -tex <S filename.bsp>", "Scale uniformly without texture lock"},
386                 {"-scale -tex <SX SY SZ filename.bsp>", "Scale non-uniformly without texture lock"},
387         };
388         HelpOptions("Scaling", 0, 80, scale, sizeof(scale)/sizeof(struct HelpOption));
389 }
390 void HelpConvert()
391 {
392         struct HelpOption convert[] = {
393                 {"-convert <filename.bsp>", "Switch that enters this mode"},
394                 {"-de <number>", "Distance epsilon for the conversion"},
395                 {"-format <converter>", "Select the converter (available: map, ase, or game names)"},
396                 {"-ne <F>", "Normal epsilon for the conversion"},
397                 {"-shadersasbitmap", "(only for ase) use the shader names as \\*BITMAP key so they work as prefabs"},
398         };
399
400         HelpOptions("Converting & Decompiling", 0, 80, convert, sizeof(convert)/sizeof(struct HelpOption));
401 }
402
403 void HelpExport()
404 {
405         struct HelpOption exportl[] = {
406                 {"-export <filename.bsp>", "Copies lightmaps from the BSP to `filename/lightmap_0000.tga` ff"}
407         };
408
409         HelpOptions("Exporting lightmaps", 0, 80, exportl, sizeof(exportl)/sizeof(struct HelpOption));
410 }
411
412 void HelpFixaas()
413 {
414         struct HelpOption fixaas[] = {
415                 {"-fixaas <filename.bsp>", "Switch that enters this mode"},
416         };
417
418         HelpOptions("Fixing AAS checksum", 0, 80, fixaas, sizeof(fixaas)/sizeof(struct HelpOption));
419 }
420
421 void HelpInfo()
422 {
423         struct HelpOption info[] = {
424                 {"-info <filename.bsp>", "Switch that enters this mode"},
425         };
426
427         HelpOptions("Get info about BSP file", 0, 80, info, sizeof(info)/sizeof(struct HelpOption));
428 }
429
430 void HelpImport()
431 {
432         struct HelpOption import[] = {
433                 {"-import <filename.bsp>", "Copies lightmaps from `filename/lightmap_0000.tga` ff into the BSP"},
434         };
435
436         HelpOptions("Importing lightmaps", 0, 80, import, sizeof(import)/sizeof(struct HelpOption));
437 }
438
439 void HelpMinimap()
440 {
441         struct HelpOption minimap[] = {
442                 {"-minimap <filename.bsp>", "Creates a minimap of the BSP, by default writes to `../gfx/filename_mini.tga`"},
443                 {"-black", "Write the minimap as a black-on-transparency RGBA32 image"},
444                 {"-boost <F>", "Sets the contrast boost value (higher values make a brighter image); contrast boost is somewhat similar to gamma, but continuous even at zero"},
445                 {"-border <F>", "Sets the amount of border pixels relative to the total image size"},
446                 {"-gray", "Write the minimap as a white-on-black GRAY8 image"},
447                 {"-keepaspect", "Ensure the aspect ratio is kept (the minimap is then letterboxed to keep aspect)"},
448                 {"-minmax <xmin ymin zmin xmax ymax zmax>", "Forces specific map dimensions (note: the minimap actually uses these dimensions, scaled to the target size while keeping aspect with centering, and 1/64 of border appended to all sides)"},
449                 {"-nokeepaspect", "Do not ensure the aspect ratio is kept (makes it easier to use the image in your code, but looks bad together with sharpening)"},
450                 {"-o <filename.tga>", "Sets the output file name"},
451                 {"-random <N>", "Sets the randomized supersampling count (cannot be combined with `-samples`)"},
452                 {"-samples <N>", "Sets the ordered supersampling count (cannot be combined with `-random`)"},
453                 {"-sharpen <F>", "Sets the sharpening coefficient"},
454                 {"-size <N>", "Sets the width and height of the output image"},
455                 {"-white", "Write the minimap as a white-on-transparency RGBA32 image"},
456         };
457
458         HelpOptions("MiniMap", 0, 80, minimap, sizeof(minimap)/sizeof(struct HelpOption));
459 }
460
461 void HelpCommon()
462 {
463         struct HelpOption common[] = {
464                 {"-connect <address>", "Talk to a NetRadiant instance using a specific XML based protocol"},
465                 {"-force", "Allow reading some broken/unsupported BSP files e.g. when decompiling, may also crash"},
466                 {"-fs_basepath <path>", "Sets the given path as main directory of the game (can be used more than once to look in multiple paths)"},
467                 {"-fs_game <gamename>", "Sets a different game directory name (default for Q3A: baseq3)"},
468                 {"-fs_homebase <dir>", "Specifies where the user home directory name is on Linux (default for Q3A: .q3a)"},
469                 {"-game <gamename>", "Load settings for the given game (default: quake3)"},
470                 {"-subdivisions <F>", "multiplier for patch subdivisions quality"},
471                 {"-threads <N>", "number of threads to use"},
472                 {"-v", "Verbose mode"}
473         };
474
475         HelpOptions("Common Options", 0, 80, common, sizeof(common)/sizeof(struct HelpOption));
476
477 }
478
479 void Help(const char* arg)
480 {
481         printf("Usage: q3map2 [stage] [common options...] [stage options...] [stage source file]\n");
482         printf("       q3map2 -help [stage]\n\n");
483
484         HelpCommon();
485
486         struct HelpOption stages[] = {
487                 {"-bsp", "BSP Stage"},
488                 {"-vis", "VIS Stage"},
489                 {"-light", "Light Stage"},
490                 {"-analize", "Analyzing BSP-like file structure"},
491                 {"-scale", "Scaling"},
492                 {"-convert", "Converting & Decompiling"},
493                 {"-export", "Exporting lightmaps"},
494                 {"-fixaas", "Fixing AAS checksum"},
495                 {"-info", "Get info about BSP file"},
496                 {"-import", "Importing lightmaps"},
497                 {"-minimap", "MiniMap"},
498         };
499         void(*help_funcs[])() = {
500                 HelpBsp,
501                 HelpVis,
502                 HelpLight,
503                 HelpAnalize,
504                 HelpScale,
505                 HelpConvert,
506                 HelpExport,
507                 HelpFixaas,
508                 HelpInfo,
509                 HelpImport,
510                 HelpMinimap
511         };
512
513         if ( arg && strlen(arg) > 0 )
514         {
515                 if ( arg[0] == '-' )
516                         arg++;
517
518                 unsigned i;
519                 for ( i = 0; i < sizeof(stages)/sizeof(struct HelpOption); i++ )
520                         if ( strcmp(arg, stages[i].name+1) == 0 )
521                         {
522                                 help_funcs[i]();
523                                 return;
524                         }
525         }
526
527         HelpOptions("Stages", 0, 80, stages, sizeof(stages)/sizeof(struct HelpOption));
528 }
529
530 /*
531    main()
532    q3map mojo...
533  */
534
535 int main( int argc, char **argv ){
536         int i, r;
537         double start, end;
538
539
540         /* we want consistent 'randomness' */
541         srand( 0 );
542
543         /* start timer */
544         start = I_FloatTime();
545
546         /* this was changed to emit version number over the network */
547         printf( Q3MAP_VERSION "\n" );
548
549         /* set exit call */
550         atexit( ExitQ3Map );
551
552         /* read general options first */
553         for ( i = 1; i < argc; i++ )
554         {
555                 /* -help */
556                 if ( !strcmp( argv[ i ], "-h" ) || !strcmp( argv[ i ], "--help" )
557                         || !strcmp( argv[ i ], "-help" ) ) {
558                         Help(argv[i+1]);
559                         return 0;
560                 }
561
562                 /* -connect */
563                 if ( !strcmp( argv[ i ], "-connect" ) ) {
564                         argv[ i ] = NULL;
565                         i++;
566                         Broadcast_Setup( argv[ i ] );
567                         argv[ i ] = NULL;
568                 }
569
570                 /* verbose */
571                 else if ( !strcmp( argv[ i ], "-v" ) ) {
572                         if ( !verbose ) {
573                                 verbose = qtrue;
574                                 argv[ i ] = NULL;
575                         }
576                 }
577
578                 /* force */
579                 else if ( !strcmp( argv[ i ], "-force" ) ) {
580                         force = qtrue;
581                         argv[ i ] = NULL;
582                 }
583
584                 /* patch subdivisions */
585                 else if ( !strcmp( argv[ i ], "-subdivisions" ) ) {
586                         argv[ i ] = NULL;
587                         i++;
588                         patchSubdivisions = atoi( argv[ i ] );
589                         argv[ i ] = NULL;
590                         if ( patchSubdivisions <= 0 ) {
591                                 patchSubdivisions = 1;
592                         }
593                 }
594
595                 /* threads */
596                 else if ( !strcmp( argv[ i ], "-threads" ) ) {
597                         argv[ i ] = NULL;
598                         i++;
599                         numthreads = atoi( argv[ i ] );
600                         argv[ i ] = NULL;
601                 }
602         }
603
604         /* init model library */
605         PicoInit();
606         PicoSetMallocFunc( safe_malloc );
607         PicoSetFreeFunc( free );
608         PicoSetPrintFunc( PicoPrintFunc );
609         PicoSetLoadFileFunc( PicoLoadFileFunc );
610         PicoSetFreeFileFunc( free );
611
612         /* set number of threads */
613         ThreadSetDefault();
614
615         /* generate sinusoid jitter table */
616         for ( i = 0; i < MAX_JITTERS; i++ )
617         {
618                 jitters[ i ] = sin( i * 139.54152147 );
619                 //%     Sys_Printf( "Jitter %4d: %f\n", i, jitters[ i ] );
620         }
621
622         /* we print out two versions, q3map's main version (since it evolves a bit out of GtkRadiant)
623            and we put the GtkRadiant version to make it easy to track with what version of Radiant it was built with */
624
625         Sys_Printf( "Q3Map         - v1.0r (c) 1999 Id Software Inc.\n" );
626         Sys_Printf( "Q3Map (ydnar) - v" Q3MAP_VERSION "\n" );
627         Sys_Printf( "NetRadiant    - v" RADIANT_VERSION " " __DATE__ " " __TIME__ "\n" );
628         Sys_Printf( "%s\n", Q3MAP_MOTD );
629
630         /* ydnar: new path initialization */
631         InitPaths( &argc, argv );
632
633         /* set game options */
634         if ( !patchSubdivisions ) {
635                 patchSubdivisions = game->patchSubdivisions;
636         }
637
638         /* check if we have enough options left to attempt something */
639         if ( argc < 2 ) {
640                 Error( "Usage: %s [general options] [options] mapfile", argv[ 0 ] );
641         }
642
643         /* fixaas */
644         if ( !strcmp( argv[ 1 ], "-fixaas" ) ) {
645                 r = FixAAS( argc - 1, argv + 1 );
646         }
647
648         /* analyze */
649         else if ( !strcmp( argv[ 1 ], "-analyze" ) ) {
650                 r = AnalyzeBSP( argc - 1, argv + 1 );
651         }
652
653         /* info */
654         else if ( !strcmp( argv[ 1 ], "-info" ) ) {
655                 r = BSPInfo( argc - 2, argv + 2 );
656         }
657
658         /* vis */
659         else if ( !strcmp( argv[ 1 ], "-vis" ) ) {
660                 r = VisMain( argc - 1, argv + 1 );
661         }
662
663         /* light */
664         else if ( !strcmp( argv[ 1 ], "-light" ) ) {
665                 r = LightMain( argc - 1, argv + 1 );
666         }
667
668         /* vlight */
669         else if ( !strcmp( argv[ 1 ], "-vlight" ) ) {
670                 Sys_Printf( "WARNING: VLight is no longer supported, defaulting to -light -fast instead\n\n" );
671                 argv[ 1 ] = "-fast";    /* eek a hack */
672                 r = LightMain( argc, argv );
673         }
674
675         /* ydnar: lightmap export */
676         else if ( !strcmp( argv[ 1 ], "-export" ) ) {
677                 r = ExportLightmapsMain( argc - 1, argv + 1 );
678         }
679
680         /* ydnar: lightmap import */
681         else if ( !strcmp( argv[ 1 ], "-import" ) ) {
682                 r = ImportLightmapsMain( argc - 1, argv + 1 );
683         }
684
685         /* ydnar: bsp scaling */
686         else if ( !strcmp( argv[ 1 ], "-scale" ) ) {
687                 r = ScaleBSPMain( argc - 1, argv + 1 );
688         }
689
690         /* ydnar: bsp conversion */
691         else if ( !strcmp( argv[ 1 ], "-convert" ) ) {
692                 r = ConvertBSPMain( argc - 1, argv + 1 );
693         }
694
695         /* div0: minimap */
696         else if ( !strcmp( argv[ 1 ], "-minimap" ) ) {
697                 r = MiniMapBSPMain( argc - 1, argv + 1 );
698         }
699
700         /* ydnar: otherwise create a bsp */
701         else{
702                 r = BSPMain( argc, argv );
703         }
704
705         /* emit time */
706         end = I_FloatTime();
707         Sys_Printf( "%9.0f seconds elapsed\n", end - start );
708
709         /* shut down connection */
710         Broadcast_Shutdown();
711
712         /* return any error code */
713         return r;
714 }