fix q3map2 -scale command line parsing
[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 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)
375 {
376         vec4_t scoeffs, tcoeffs;
377         float md;
378         m4x4_t solvematrix;
379
380         vec3_t norm;
381         vec3_t dab, dac;
382         VectorSubtract(bxyz, axyz, dab);
383         VectorSubtract(cxyz, axyz, dac);
384         CrossProduct(dab, dac, norm);
385         
386         // assume:
387         //   s = f(x, y, z)
388         //   s(v + norm) = s(v) when n ortho xyz
389         
390         // s(v) = DotProduct(v, scoeffs) + scoeffs[3]
391
392         // solve:
393         //   scoeffs * (axyz, 1) == ast[0]
394         //   scoeffs * (bxyz, 1) == bst[0]
395         //   scoeffs * (cxyz, 1) == cst[0]
396         //   scoeffs * (norm, 0) == 0
397         // scoeffs * [axyz, 1 | bxyz, 1 | cxyz, 1 | norm, 0] = [ast[0], bst[0], cst[0], 0]
398         solvematrix[0] = axyz[0];
399         solvematrix[4] = axyz[1];
400         solvematrix[8] = axyz[2];
401         solvematrix[12] = 1;
402         solvematrix[1] = bxyz[0];
403         solvematrix[5] = bxyz[1];
404         solvematrix[9] = bxyz[2];
405         solvematrix[13] = 1;
406         solvematrix[2] = cxyz[0];
407         solvematrix[6] = cxyz[1];
408         solvematrix[10] = cxyz[2];
409         solvematrix[14] = 1;
410         solvematrix[3] = norm[0];
411         solvematrix[7] = norm[1];
412         solvematrix[11] = norm[2];
413         solvematrix[15] = 0;
414
415         md = m4_det(solvematrix);
416         if(md*md < 1e-10)
417         {
418                 Sys_Printf("Cannot invert some matrix, some texcoords aren't extrapolated!");
419                 return;
420         }
421
422         m4x4_invert(solvematrix);
423
424         scoeffs[0] = ast[0];
425         scoeffs[1] = bst[0];
426         scoeffs[2] = cst[0];
427         scoeffs[3] = 0;
428         m4x4_transform_vec4(solvematrix, scoeffs);
429         tcoeffs[0] = ast[1];
430         tcoeffs[1] = bst[1];
431         tcoeffs[2] = cst[1];
432         tcoeffs[3] = 0;
433         m4x4_transform_vec4(solvematrix, tcoeffs);
434
435         ast_out[0] = scoeffs[0] * axyz_new[0] + scoeffs[1] * axyz_new[1] + scoeffs[2] * axyz_new[2] + scoeffs[3];
436         ast_out[1] = tcoeffs[0] * axyz_new[0] + tcoeffs[1] * axyz_new[1] + tcoeffs[2] * axyz_new[2] + tcoeffs[3];
437         bst_out[0] = scoeffs[0] * bxyz_new[0] + scoeffs[1] * bxyz_new[1] + scoeffs[2] * bxyz_new[2] + scoeffs[3];
438         bst_out[1] = tcoeffs[0] * bxyz_new[0] + tcoeffs[1] * bxyz_new[1] + tcoeffs[2] * bxyz_new[2] + tcoeffs[3];
439         cst_out[0] = scoeffs[0] * cxyz_new[0] + scoeffs[1] * cxyz_new[1] + scoeffs[2] * cxyz_new[2] + scoeffs[3];
440         cst_out[1] = tcoeffs[0] * cxyz_new[0] + tcoeffs[1] * cxyz_new[1] + tcoeffs[2] * cxyz_new[2] + tcoeffs[3];
441 }
442
443 /*
444 ScaleBSPMain()
445 amaze and confuse your enemies with wierd scaled maps!
446 */
447
448 int ScaleBSPMain( int argc, char **argv )
449 {
450         int                     i, j;
451         float           f, a;
452         vec3_t scale;
453         vec3_t          vec;
454         char            str[ 1024 ];
455         int uniform, axis;
456         qboolean texscale;
457         float *old_xyzst = NULL;
458         
459         
460         /* arg checking */
461         if( argc < 3 )
462         {
463                 Sys_Printf( "Usage: q3map [-v] -scale [-tex] <value> <mapname>\n" );
464                 return 0;
465         }
466         
467         /* get scale */
468         scale[2] = scale[1] = scale[0] = atof( argv[ argc - 2 ] );
469         if(argc >= 4)
470                 scale[1] = scale[0] = atof( argv[ argc - 3 ] );
471         if(argc >= 5)
472                 scale[0] = atof( argv[ argc - 4 ] );
473
474         texscale = !strcmp(argv[1], "-tex");
475         
476         uniform = ((scale[0] == scale[1]) && (scale[1] == scale[2]));
477
478         if( scale[0] == 0.0f || scale[1] == 0.0f || scale[2] == 0.0f )
479         {
480                 Sys_Printf( "Usage: q3map [-v] -scale [-tex] <value> <mapname>\n" );
481                 Sys_Printf( "Non-zero scale value required.\n" );
482                 return 0;
483         }
484         
485         /* do some path mangling */
486         strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
487         StripExtension( source );
488         DefaultExtension( source, ".bsp" );
489         
490         /* load the bsp */
491         Sys_Printf( "Loading %s\n", source );
492         LoadBSPFile( source );
493         ParseEntities();
494         
495         /* note it */
496         Sys_Printf( "--- ScaleBSP ---\n" );
497         Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
498         
499         /* scale entity keys */
500         for( i = 0; i < numBSPEntities && i < numEntities; i++ )
501         {
502                 /* scale origin */
503                 GetVectorForKey( &entities[ i ], "origin", vec );
504                 if( (vec[ 0 ] || vec[ 1 ] || vec[ 2 ]) )
505                 {
506                         vec[0] *= scale[0];
507                         vec[1] *= scale[1];
508                         vec[2] *= scale[2];
509                         sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
510                         SetKeyValue( &entities[ i ], "origin", str );
511                 }
512
513                 a = FloatForKey( &entities[ i ], "angle" );
514                 if(a == -1 || a == -2) // z scale
515                         axis = 2;
516                 else if(fabs(sin(DEG2RAD(a))) < 0.707)
517                         axis = 0;
518                 else
519                         axis = 1;
520                 
521                 /* scale door lip */
522                 f = FloatForKey( &entities[ i ], "lip" );
523                 if( f )
524                 {
525                         f *= scale[axis];
526                         sprintf( str, "%f", f );
527                         SetKeyValue( &entities[ i ], "lip", str );
528                 }
529                 
530                 /* scale plat height */
531                 f = FloatForKey( &entities[ i ], "height" );
532                 if( f )
533                 {
534                         f *= scale[2];
535                         sprintf( str, "%f", f );
536                         SetKeyValue( &entities[ i ], "height", str );
537                 }
538
539                 // TODO maybe allow a definition file for entities to specify which values are scaled how?
540         }
541         
542         /* scale models */
543         for( i = 0; i < numBSPModels; i++ )
544         {
545                 bspModels[ i ].mins[0] *= scale[0];
546                 bspModels[ i ].mins[1] *= scale[1];
547                 bspModels[ i ].mins[2] *= scale[2];
548                 bspModels[ i ].maxs[0] *= scale[0];
549                 bspModels[ i ].maxs[1] *= scale[1];
550                 bspModels[ i ].maxs[2] *= scale[2];
551         }
552         
553         /* scale nodes */
554         for( i = 0; i < numBSPNodes; i++ )
555         {
556                 bspNodes[ i ].mins[0] *= scale[0];
557                 bspNodes[ i ].mins[1] *= scale[1];
558                 bspNodes[ i ].mins[2] *= scale[2];
559                 bspNodes[ i ].maxs[0] *= scale[0];
560                 bspNodes[ i ].maxs[1] *= scale[1];
561                 bspNodes[ i ].maxs[2] *= scale[2];
562         }
563         
564         /* scale leafs */
565         for( i = 0; i < numBSPLeafs; i++ )
566         {
567                 bspLeafs[ i ].mins[0] *= scale[0];
568                 bspLeafs[ i ].mins[1] *= scale[1];
569                 bspLeafs[ i ].mins[2] *= scale[2];
570                 bspLeafs[ i ].maxs[0] *= scale[0];
571                 bspLeafs[ i ].maxs[1] *= scale[1];
572                 bspLeafs[ i ].maxs[2] *= scale[2];
573         }
574         
575         if(texscale)
576         {
577                 Sys_Printf("Using texture unlocking (and probably breaking texture alignment a lot)\n");
578                 old_xyzst = safe_malloc(sizeof(*old_xyzst) * numBSPDrawVerts * 5);
579                 for(i = 0; i < numBSPDrawVerts; i++)
580                 {
581                         old_xyzst[5*i+0] = bspDrawVerts[i].xyz[0];
582                         old_xyzst[5*i+1] = bspDrawVerts[i].xyz[1];
583                         old_xyzst[5*i+2] = bspDrawVerts[i].xyz[2];
584                         old_xyzst[5*i+3] = bspDrawVerts[i].st[0];
585                         old_xyzst[5*i+4] = bspDrawVerts[i].st[1];
586                 }
587         }
588
589         /* scale drawverts */
590         for( i = 0; i < numBSPDrawVerts; i++ )
591         {
592                 bspDrawVerts[i].xyz[0] *= scale[0];
593                 bspDrawVerts[i].xyz[1] *= scale[1];
594                 bspDrawVerts[i].xyz[2] *= scale[2];
595                 bspDrawVerts[i].normal[0] /= scale[0];
596                 bspDrawVerts[i].normal[1] /= scale[1];
597                 bspDrawVerts[i].normal[2] /= scale[2];
598                 VectorNormalize(bspDrawVerts[i].normal, bspDrawVerts[i].normal);
599         }
600
601         if(texscale)
602         {
603                 for(i = 0; i < numBSPDrawSurfaces; i++)
604                 {
605                         switch(bspDrawSurfaces[i].surfaceType)
606                         {
607                                 case SURFACE_FACE:
608                                 case SURFACE_META:
609                                         if(bspDrawSurfaces[i].numIndexes % 3)
610                                                 Error("Not a triangulation!");
611                                         for(j = bspDrawSurfaces[i].firstIndex; j < bspDrawSurfaces[i].firstIndex + bspDrawSurfaces[i].numIndexes; j += 3)
612                                         {
613                                                 int ia = bspDrawIndexes[j] + bspDrawSurfaces[i].firstVert, ib = bspDrawIndexes[j+1] + bspDrawSurfaces[i].firstVert, ic = bspDrawIndexes[j+2] + bspDrawSurfaces[i].firstVert;
614                                                 bspDrawVert_t *a = &bspDrawVerts[ia], *b = &bspDrawVerts[ib], *c = &bspDrawVerts[ic];
615                                                 float *oa = &old_xyzst[ia*5], *ob = &old_xyzst[ib*5], *oc = &old_xyzst[ic*5];
616                                                 // extrapolate:
617                                                 //   a->xyz -> oa
618                                                 //   b->xyz -> ob
619                                                 //   c->xyz -> oc
620                                                 ExtrapolateTexcoords(
621                                                         &oa[0], &oa[3],
622                                                         &ob[0], &ob[3],
623                                                         &oc[0], &oc[3],
624                                                         a->xyz, a->st,
625                                                         b->xyz, b->st,
626                                                         c->xyz, c->st);
627                                         }
628                                         break;
629                         }
630                 }
631         }
632         
633         /* scale planes */
634         if(uniform)
635         {
636                 for( i = 0; i < numBSPPlanes; i++ )
637                 {
638                         bspPlanes[ i ].dist *= scale[0];
639                 }
640         }
641         else
642         {
643                 for( i = 0; i < numBSPPlanes; i++ )
644                 {
645                         bspPlanes[ i ].normal[0] /= scale[0];
646                         bspPlanes[ i ].normal[1] /= scale[1];
647                         bspPlanes[ i ].normal[2] /= scale[2];
648                         f = 1/VectorLength(bspPlanes[i].normal);
649                         VectorScale(bspPlanes[i].normal, f, bspPlanes[i].normal);
650                         bspPlanes[ i ].dist *= f;
651                 }
652         }
653         
654         /* scale gridsize */
655         GetVectorForKey( &entities[ 0 ], "gridsize", vec );
656         if( (vec[ 0 ] + vec[ 1 ] + vec[ 2 ]) == 0.0f )
657                 VectorCopy( gridSize, vec );
658         vec[0] *= scale[0];
659         vec[1] *= scale[1];
660         vec[2] *= scale[2];
661         sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
662         SetKeyValue( &entities[ 0 ], "gridsize", str );
663
664         /* inject command line parameters */
665         InjectCommandLine(argv, 0, argc - 1);
666         
667         /* write the bsp */
668         UnparseEntities();
669         StripExtension( source );
670         DefaultExtension( source, "_s.bsp" );
671         Sys_Printf( "Writing %s\n", source );
672         WriteBSPFile( source );
673         
674         /* return to sender */
675         return 0;
676 }
677
678
679
680 /*
681 ConvertBSPMain()
682 main argument processing function for bsp conversion
683 */
684
685 int ConvertBSPMain( int argc, char **argv )
686 {
687         int             i;
688         int             (*convertFunc)( char * );
689         game_t  *convertGame;
690         
691         
692         /* set default */
693         convertFunc = ConvertBSPToASE;
694         convertGame = NULL;
695         
696         /* arg checking */
697         if( argc < 1 )
698         {
699                 Sys_Printf( "Usage: q3map -scale <value> [-v] <mapname>\n" );
700                 return 0;
701         }
702         
703         /* process arguments */
704         for( i = 1; i < (argc - 1); i++ )
705         {
706                 /* -format map|ase|... */
707                 if( !strcmp( argv[ i ],  "-format" ) )
708                 {
709                         i++;
710                         if( !Q_stricmp( argv[ i ], "ase" ) )
711                                 convertFunc = ConvertBSPToASE;
712                         else if( !Q_stricmp( argv[ i ], "map" ) )
713                                 convertFunc = ConvertBSPToMap;
714                         else
715                         {
716                                 convertGame = GetGame( argv[ i ] );
717                                 if( convertGame == NULL )
718                                         Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
719                         }
720                 }
721                 else if( !strcmp( argv[ i ],  "-ne" ) )
722                 {
723                         normalEpsilon = atof( argv[ i + 1 ] );
724                         i++;
725                         Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
726                 }
727                 else if( !strcmp( argv[ i ],  "-de" ) )
728                 {
729                         distanceEpsilon = atof( argv[ i + 1 ] );
730                         i++;
731                         Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
732                 }
733                 else if( !strcmp( argv[ i ],  "-shadersasbitmap" ) )
734                         shadersAsBitmap = qtrue;
735         }
736         
737         /* clean up map name */
738         strcpy( source, ExpandArg( argv[ i ] ) );
739         StripExtension( source );
740         DefaultExtension( source, ".bsp" );
741         
742         LoadShaderInfo();
743         
744         Sys_Printf( "Loading %s\n", source );
745         
746         /* ydnar: load surface file */
747         //%     LoadSurfaceExtraFile( source );
748         
749         LoadBSPFile( source );
750         
751         /* parse bsp entities */
752         ParseEntities();
753         
754         /* bsp format convert? */
755         if( convertGame != NULL )
756         {
757                 /* set global game */
758                 game = convertGame;
759                 
760                 /* write bsp */
761                 StripExtension( source );
762                 DefaultExtension( source, "_c.bsp" );
763                 Sys_Printf( "Writing %s\n", source );
764                 WriteBSPFile( source );
765                 
766                 /* return to sender */
767                 return 0;
768         }
769         
770         /* normal convert */
771         return convertFunc( source );
772 }
773
774
775
776 /*
777 main()
778 q3map mojo...
779 */
780
781 int main( int argc, char **argv )
782 {
783         int             i, r;
784         double  start, end;
785         
786         
787         /* we want consistent 'randomness' */
788         srand( 0 );
789         
790         /* start timer */
791         start = I_FloatTime();
792
793         /* this was changed to emit version number over the network */
794         printf( Q3MAP_VERSION "\n" );
795         
796         /* set exit call */
797         atexit( ExitQ3Map );
798         
799         /* read general options first */
800         for( i = 1; i < argc; i++ )
801         {
802                 /* -connect */
803                 if( !strcmp( argv[ i ], "-connect" ) )
804                 {
805                         argv[ i ] = NULL;
806                         i++;
807                         Broadcast_Setup( argv[ i ] );
808                         argv[ i ] = NULL;
809                 }
810                 
811                 /* verbose */
812                 else if( !strcmp( argv[ i ], "-v" ) )
813                 {
814                         verbose = qtrue;
815                         argv[ i ] = NULL;
816                 }
817                 
818                 /* force */
819                 else if( !strcmp( argv[ i ], "-force" ) )
820                 {
821                         force = qtrue;
822                         argv[ i ] = NULL;
823                 }
824                 
825                 /* patch subdivisions */
826                 else if( !strcmp( argv[ i ], "-subdivisions" ) )
827                 {
828                         argv[ i ] = NULL;
829                         i++;
830                         patchSubdivisions = atoi( argv[ i ] );
831                         argv[ i ] = NULL;
832                         if( patchSubdivisions <= 0 )
833                                 patchSubdivisions = 1;
834                 }
835                 
836                 /* threads */
837                 else if( !strcmp( argv[ i ], "-threads" ) )
838                 {
839                         argv[ i ] = NULL;
840                         i++;
841                         numthreads = atoi( argv[ i ] );
842                         argv[ i ] = NULL;
843                 }
844         }
845         
846         /* init model library */
847         PicoInit();
848         PicoSetMallocFunc( safe_malloc );
849         PicoSetFreeFunc( free );
850         PicoSetPrintFunc( PicoPrintFunc );
851         PicoSetLoadFileFunc( PicoLoadFileFunc );
852         PicoSetFreeFileFunc( free );
853         
854         /* set number of threads */
855         ThreadSetDefault();
856         
857         /* generate sinusoid jitter table */
858         for( i = 0; i < MAX_JITTERS; i++ )
859         {
860                 jitters[ i ] = sin( i * 139.54152147 );
861                 //%     Sys_Printf( "Jitter %4d: %f\n", i, jitters[ i ] );
862         }
863         
864         /* we print out two versions, q3map's main version (since it evolves a bit out of GtkRadiant)
865            and we put the GtkRadiant version to make it easy to track with what version of Radiant it was built with */
866         
867         Sys_Printf( "Q3Map         - v1.0r (c) 1999 Id Software Inc.\n" );
868         Sys_Printf( "Q3Map (ydnar) - v" Q3MAP_VERSION "\n" );
869         Sys_Printf( "NetRadiant    - v" RADIANT_VERSION " " __DATE__ " " __TIME__ "\n" );
870         Sys_Printf( "%s\n", Q3MAP_MOTD );
871         
872         /* ydnar: new path initialization */
873         InitPaths( &argc, argv );
874         
875         /* check if we have enough options left to attempt something */
876         if( argc < 2 )
877                 Error( "Usage: %s [general options] [options] mapfile", argv[ 0 ] );
878         
879         /* fixaas */
880         if( !strcmp( argv[ 1 ], "-fixaas" ) )
881                 r = FixAAS( argc - 1, argv + 1 );
882         
883         /* analyze */
884         else if( !strcmp( argv[ 1 ], "-analyze" ) )
885                 r = AnalyzeBSP( argc - 1, argv + 1 );
886         
887         /* info */
888         else if( !strcmp( argv[ 1 ], "-info" ) )
889                 r = BSPInfo( argc - 2, argv + 2 );
890         
891         /* vis */
892         else if( !strcmp( argv[ 1 ], "-vis" ) )
893                 r = VisMain( argc - 1, argv + 1 );
894         
895         /* light */
896         else if( !strcmp( argv[ 1 ], "-light" ) )
897                 r = LightMain( argc - 1, argv + 1 );
898         
899         /* vlight */
900         else if( !strcmp( argv[ 1 ], "-vlight" ) )
901         {
902                 Sys_Printf( "WARNING: VLight is no longer supported, defaulting to -light -fast instead\n\n" );
903                 argv[ 1 ] = "-fast";    /* eek a hack */
904                 r = LightMain( argc, argv );
905         }
906         
907         /* ydnar: lightmap export */
908         else if( !strcmp( argv[ 1 ], "-export" ) )
909                 r = ExportLightmapsMain( argc - 1, argv + 1 );
910         
911         /* ydnar: lightmap import */
912         else if( !strcmp( argv[ 1 ], "-import" ) )
913                 r = ImportLightmapsMain( argc - 1, argv + 1 );
914         
915         /* ydnar: bsp scaling */
916         else if( !strcmp( argv[ 1 ], "-scale" ) )
917                 r = ScaleBSPMain( argc - 1, argv + 1 );
918         
919         /* ydnar: bsp conversion */
920         else if( !strcmp( argv[ 1 ], "-convert" ) )
921                 r = ConvertBSPMain( argc - 1, argv + 1 );
922         
923         /* ydnar: otherwise create a bsp */
924         else
925                 r = BSPMain( argc, argv );
926         
927         /* emit time */
928         end = I_FloatTime();
929         Sys_Printf( "%9.0f seconds elapsed\n", end - start );
930         
931         /* shut down connection */
932         Broadcast_Shutdown();
933         
934         /* return any error code */
935         return r;
936 }