try to eliminate MAX_MAP_PLANES limits
[divverent/netradiant.git] / tools / quake3 / q3map2 / bsp.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 BSP_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41 /* -------------------------------------------------------------------------------
42
43 functions
44
45 ------------------------------------------------------------------------------- */
46
47
48 /*
49 ProcessAdvertisements()
50 copies advertisement info into the BSP structures
51 */
52
53 static void ProcessAdvertisements( void ) {
54         int                                     i;
55         const char*                     className;
56         const char*                     modelKey;
57         int                                     modelNum;
58         bspModel_t*                     adModel;
59         bspDrawSurface_t*       adSurface;
60
61         Sys_FPrintf( SYS_VRB, "--- ProcessAdvertisements ---\n" );
62
63         for( i = 0; i < numEntities; i++ ) {
64
65                 /* is an advertisement? */
66                 className = ValueForKey( &entities[ i ], "classname" );
67
68                 if( !Q_stricmp( "advertisement", className ) ) {
69                         
70                         modelKey = ValueForKey( &entities[ i ], "model" );
71
72                         if( strlen( modelKey ) > MAX_QPATH - 1 ) {
73                                 Error( "Model Key for entity exceeds ad struct string length." );
74                         } else {
75                                 if( numBSPAds < MAX_MAP_ADVERTISEMENTS ) {
76                                         bspAds[numBSPAds].cellId = IntForKey( &entities[ i ], "cellId" );
77                                         strncpy( bspAds[numBSPAds].model, modelKey, sizeof( bspAds[numBSPAds].model ) );
78
79                                         modelKey++;
80                                         modelNum = atoi( modelKey );
81                                         adModel = &bspModels[modelNum];
82                                         
83                                         if( adModel->numBSPSurfaces != 1 ) {
84                                                 Error( "Ad cell id %d has more than one surface.", bspAds[numBSPAds].cellId );
85                                         }
86
87                                         adSurface = &bspDrawSurfaces[adModel->firstBSPSurface];
88                                         
89                                         // store the normal for use at run time.. all ad verts are assumed to 
90                                         // have identical normals (because they should be a simple rectangle)
91                                         // so just use the first vert's normal
92                                         VectorCopy( bspDrawVerts[adSurface->firstVert].normal, bspAds[numBSPAds].normal );
93
94                                         // store the ad quad for quick use at run time
95                                         if( adSurface->surfaceType == MST_PATCH ) {
96                                                 int v0 = adSurface->firstVert + adSurface->patchHeight - 1;
97                                                 int v1 = adSurface->firstVert + adSurface->numVerts - 1;
98                                                 int v2 = adSurface->firstVert + adSurface->numVerts - adSurface->patchWidth;
99                                                 int v3 = adSurface->firstVert;
100                                                 VectorCopy( bspDrawVerts[v0].xyz, bspAds[numBSPAds].rect[0] );
101                                                 VectorCopy( bspDrawVerts[v1].xyz, bspAds[numBSPAds].rect[1] );
102                                                 VectorCopy( bspDrawVerts[v2].xyz, bspAds[numBSPAds].rect[2] );
103                                                 VectorCopy( bspDrawVerts[v3].xyz, bspAds[numBSPAds].rect[3] );
104                                         } else {
105                                                 Error( "Ad cell %d has an unsupported Ad Surface type.", bspAds[numBSPAds].cellId );
106                                         }
107
108                                         numBSPAds++;
109                                 } else {
110                                         Error( "Maximum number of map advertisements exceeded." );
111                                 }
112                         }
113                 }
114         }
115
116         Sys_FPrintf( SYS_VRB, "%9d in-game advertisements\n", numBSPAds );
117 }
118
119 /*
120 SetCloneModelNumbers() - ydnar
121 sets the model numbers for brush entities
122 */
123
124 static void SetCloneModelNumbers( void )
125 {
126         int                     i, j;
127         int                     models;
128         char            modelValue[ 10 ];
129         const char      *value, *value2, *value3;
130         
131         
132         /* start with 1 (worldspawn is model 0) */
133         models = 1;
134         for( i = 1; i < numEntities; i++ )
135         {
136                 /* only entities with brushes or patches get a model number */
137                 if( entities[ i ].brushes == NULL && entities[ i ].patches == NULL )
138                         continue;
139                 
140                 /* is this a clone? */
141                 value = ValueForKey( &entities[ i ], "_clone" );
142                 if( value[ 0 ] != '\0' )
143                         continue;
144                 
145                 /* add the model key */
146                 sprintf( modelValue, "*%d", models );
147                 SetKeyValue( &entities[ i ], "model", modelValue );
148                 
149                 /* increment model count */
150                 models++;
151         }
152         
153         /* fix up clones */
154         for( i = 1; i < numEntities; i++ )
155         {
156                 /* only entities with brushes or patches get a model number */
157                 if( entities[ i ].brushes == NULL && entities[ i ].patches == NULL )
158                         continue;
159                 
160                 /* is this a clone? */
161                 value = ValueForKey( &entities[ i ], "_ins" );
162                 if( value[ 0 ] == '\0' )
163                         value = ValueForKey( &entities[ i ], "_instance" );
164                 if( value[ 0 ] == '\0' )
165                         value = ValueForKey( &entities[ i ], "_clone" );
166                 if( value[ 0 ] == '\0' )
167                         continue;
168                 
169                 /* find an entity with matching clone name */
170                 for( j = 0; j < numEntities; j++ )
171                 {
172                         /* is this a clone parent? */
173                         value2 = ValueForKey( &entities[ j ], "_clonename" );
174                         if( value2[ 0 ] == '\0' )
175                                 continue;
176                         
177                         /* do they match? */
178                         if( strcmp( value, value2 ) == 0 )
179                         {
180                                 /* get the model num */
181                                 value3 = ValueForKey( &entities[ j ], "model" );
182                                 if( value3[ 0 ] == '\0' )
183                                 {
184                                         Sys_Printf( "WARNING: Cloned entity %s referenced entity without model\n", value2 );
185                                         continue;
186                                 }
187                                 models = atoi( &value2[ 1 ] );
188                                 
189                                 /* add the model key */
190                                 sprintf( modelValue, "*%d", models );
191                                 SetKeyValue( &entities[ i ], "model", modelValue );
192                                 
193                                 /* nuke the brushes/patches for this entity (fixme: leak!) */
194                                 entities[ i ].brushes = NULL;
195                                 entities[ i ].patches = NULL;
196                         }
197                 }
198         }
199 }
200
201
202
203 /*
204 FixBrushSides() - ydnar
205 matches brushsides back to their appropriate drawsurface and shader
206 */
207
208 static void FixBrushSides( entity_t *e )
209 {
210         int                                     i;
211         mapDrawSurface_t        *ds;
212         sideRef_t                       *sideRef;
213         bspBrushSide_t          *side;
214         
215         
216         /* note it */
217         Sys_FPrintf( SYS_VRB, "--- FixBrushSides ---\n" );
218         
219         /* walk list of drawsurfaces */
220         for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
221         {
222                 /* get surface and try to early out */
223                 ds = &mapDrawSurfs[ i ];
224                 if( ds->outputNum < 0 )
225                         continue;
226                 
227                 /* walk sideref list */
228                 for( sideRef = ds->sideRef; sideRef != NULL; sideRef = sideRef->next )
229                 {
230                         /* get bsp brush side */
231                         if( sideRef->side == NULL || sideRef->side->outputNum < 0 )
232                                 continue;
233                         side = &bspBrushSides[ sideRef->side->outputNum ];
234                         
235                         /* set drawsurface */
236                         side->surfaceNum = ds->outputNum;
237                         //%     Sys_FPrintf( SYS_VRB, "DS: %7d Side: %7d     ", ds->outputNum, sideRef->side->outputNum );
238                         
239                         /* set shader */
240                         if( strcmp( bspShaders[ side->shaderNum ].shader, ds->shaderInfo->shader ) )
241                         {
242                                 //%     Sys_FPrintf( SYS_VRB, "Remapping %s to %s\n", bspShaders[ side->shaderNum ].shader, ds->shaderInfo->shader );
243                                 side->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags );
244                         }
245                 }
246         }
247 }
248
249
250
251 /*
252 ProcessWorldModel()
253 creates a full bsp + surfaces for the worldspawn entity
254 */
255
256 void ProcessWorldModel( void )
257 {
258         int                     i, s;
259         entity_t        *e;
260         tree_t          *tree;
261         face_t          *faces;
262         qboolean        ignoreLeaks, leaked;
263         xmlNodePtr      polyline, leaknode;
264         char            level[ 2 ], shader[ 1024 ];
265         const char      *value;
266         
267         
268         /* sets integer blockSize from worldspawn "_blocksize" key if it exists */
269         value = ValueForKey( &entities[ 0 ], "_blocksize" );
270         if( value[ 0 ] == '\0' )
271                 value = ValueForKey( &entities[ 0 ], "blocksize" );
272         if( value[ 0 ] == '\0' )
273                 value = ValueForKey( &entities[ 0 ], "chopsize" );      /* sof2 */
274         if( value[ 0 ] != '\0' )
275         {
276                 /* scan 3 numbers */
277                 s = sscanf( value, "%d %d %d", &blockSize[ 0 ], &blockSize[ 1 ], &blockSize[ 2 ] );
278                 
279                 /* handle legacy case */
280                 if( s == 1 )
281                 {
282                         blockSize[ 1 ] = blockSize[ 0 ];
283                         blockSize[ 2 ] = blockSize[ 0 ];
284                 }
285         }
286         Sys_Printf( "block size = { %d %d %d }\n", blockSize[ 0 ], blockSize[ 1 ], blockSize[ 2 ] );
287         
288         /* sof2: ignore leaks? */
289         value = ValueForKey( &entities[ 0 ], "_ignoreleaks" );  /* ydnar */
290         if( value[ 0 ] == '\0' )
291                 value = ValueForKey( &entities[ 0 ], "ignoreleaks" );
292         if( value[ 0 ] == '1' )
293                 ignoreLeaks = qtrue;
294         else
295                 ignoreLeaks = qfalse;
296         
297         /* begin worldspawn model */
298         BeginModel();
299         e = &entities[ 0 ];
300         e->firstDrawSurf = 0;
301         
302         /* ydnar: gs mods */
303         ClearMetaTriangles();
304
305         /* check for patches with adjacent edges that need to lod together */
306         PatchMapDrawSurfs( e );
307
308         /* build an initial bsp tree using all of the sides of all of the structural brushes */
309         faces = MakeStructuralBSPFaceList( entities[ 0 ].brushes );
310         tree = FaceBSP( faces );
311         MakeTreePortals( tree );
312         FilterStructuralBrushesIntoTree( e, tree );
313         
314         /* see if the bsp is completely enclosed */
315         if( FloodEntities( tree ) || ignoreLeaks )
316         {
317                 /* rebuild a better bsp tree using only the sides that are visible from the inside */
318                 FillOutside( tree->headnode );
319
320                 /* chop the sides to the convex hull of their visible fragments, giving us the smallest polygons */
321                 ClipSidesIntoTree( e, tree );
322                 
323                 /* build a visible face tree */
324                 faces = MakeVisibleBSPFaceList( entities[ 0 ].brushes );
325                 FreeTree( tree );
326                 tree = FaceBSP( faces );
327                 MakeTreePortals( tree );
328                 FilterStructuralBrushesIntoTree( e, tree );
329                 leaked = qfalse;
330                 
331                 /* ydnar: flood again for skybox */
332                 if( skyboxPresent )
333                         FloodEntities( tree );
334         }
335         else
336         {
337                 Sys_FPrintf( SYS_NOXML, "**********************\n" );
338                 Sys_FPrintf( SYS_NOXML, "******* leaked *******\n" );
339                 Sys_FPrintf( SYS_NOXML, "**********************\n" );
340                 polyline = LeakFile( tree );
341                 leaknode = xmlNewNode( NULL, "message" );
342                 xmlNodeSetContent( leaknode, "MAP LEAKED\n" );
343                 xmlAddChild( leaknode, polyline );
344                 level[0] = (int) '0' + SYS_ERR;
345                 level[1] = 0;
346                 xmlSetProp( leaknode, "level", (char*) &level );
347                 xml_SendNode( leaknode );
348                 if( leaktest )
349                 {
350                         Sys_Printf ("--- MAP LEAKED, ABORTING LEAKTEST ---\n");
351                         exit( 0 );
352                 }
353                 leaked = qtrue;
354                 
355                 /* chop the sides to the convex hull of their visible fragments, giving us the smallest polygons */
356                 ClipSidesIntoTree( e, tree );
357         }
358         
359         /* save out information for visibility processing */
360         NumberClusters( tree );
361         if( !leaked )
362                 WritePortalFile( tree );
363         
364         /* flood from entities */
365         FloodAreas( tree );
366         
367         /* create drawsurfs for triangle models */
368         AddTriangleModels( e );
369         
370         /* create drawsurfs for surface models */
371         AddEntitySurfaceModels( e );
372         
373         /* generate bsp brushes from map brushes */
374         EmitBrushes( e->brushes, &e->firstBrush, &e->numBrushes );
375         
376         /* add references to the detail brushes */
377         FilterDetailBrushesIntoTree( e, tree );
378         
379         /* drawsurfs that cross fog boundaries will need to be split along the fog boundary */
380         if( !nofog )
381                 FogDrawSurfaces( e );
382         
383         /* subdivide each drawsurf as required by shader tesselation */
384         if( !nosubdivide )
385                 SubdivideFaceSurfaces( e, tree );
386         
387         /* add in any vertexes required to fix t-junctions */
388         if( !notjunc )
389                 FixTJunctions( e );
390         
391         /* ydnar: classify the surfaces */
392         ClassifyEntitySurfaces( e );
393         
394         /* ydnar: project decals */
395         MakeEntityDecals( e );
396         
397         /* ydnar: meta surfaces */
398         MakeEntityMetaTriangles( e );
399         SmoothMetaTriangles();
400         FixMetaTJunctions();
401         MergeMetaTriangles();
402         
403         /* ydnar: debug portals */
404         if( debugPortals )
405                 MakeDebugPortalSurfs( tree );
406         
407         /* ydnar: fog hull */
408         value = ValueForKey( &entities[ 0 ], "_foghull" );
409         if( value[ 0 ] != '\0' )
410         {
411                 sprintf( shader, "textures/%s", value );
412                 MakeFogHullSurfs( e, tree, shader );
413         }
414         
415         /* ydnar: bug 645: do flares for lights */
416         for( i = 0; i < numEntities && emitFlares; i++ )
417         {
418                 entity_t        *light, *target;
419                 const char      *value, *flareShader;
420                 vec3_t          origin, targetOrigin, normal, color;
421                 int                     lightStyle;
422                 
423                 
424                 /* get light */
425                 light = &entities[ i ];
426                 value = ValueForKey( light, "classname" );
427                 if( !strcmp( value, "light" ) )
428                 {
429                         /* get flare shader */
430                         flareShader = ValueForKey( light, "_flareshader" );
431                         value = ValueForKey( light, "_flare" );
432                         if( flareShader[ 0 ] != '\0' || value[ 0 ] != '\0' )
433                         {
434                                 /* get specifics */
435                                 GetVectorForKey( light, "origin", origin );
436                                 GetVectorForKey( light, "_color", color );
437                                 lightStyle = IntForKey( light, "_style" );
438                                 if( lightStyle == 0 )
439                                         lightStyle = IntForKey( light, "style" );
440                                 
441                                 /* handle directional spotlights */
442                                 value = ValueForKey( light, "target" );
443                                 if( value[ 0 ] != '\0' )
444                                 {
445                                         /* get target light */
446                                         target = FindTargetEntity( value );
447                                         if( target != NULL )
448                                         {
449                                                 GetVectorForKey( target, "origin", targetOrigin );
450                                                 VectorSubtract( targetOrigin, origin, normal );
451                                                 VectorNormalize( normal, normal );
452                                         }
453                                 }
454                                 else
455                                         //%     VectorClear( normal );
456                                         VectorSet( normal, 0, 0, -1 );
457                                 
458                                 /* create the flare surface (note shader defaults automatically) */
459                                 DrawSurfaceForFlare( mapEntityNum, origin, normal, color, (char*) flareShader, lightStyle );
460                         }
461                 }
462         }
463         
464         /* add references to the final drawsurfs in the apropriate clusters */
465         FilterDrawsurfsIntoTree( e, tree );
466         
467         /* match drawsurfaces back to original brushsides (sof2) */
468         FixBrushSides( e );
469         
470         /* finish */
471         EndModel( e, tree->headnode );
472         FreeTree( tree );
473 }
474
475
476
477 /*
478 ProcessSubModel()
479 creates bsp + surfaces for other brush models
480 */
481
482 void ProcessSubModel( void )
483 {
484         entity_t        *e;
485         tree_t          *tree;
486         brush_t         *b, *bc;
487         node_t          *node;
488         
489         
490         /* start a brush model */
491         BeginModel();
492         e = &entities[ mapEntityNum ];
493         e->firstDrawSurf = numMapDrawSurfs;
494         
495         /* ydnar: gs mods */
496         ClearMetaTriangles();
497         
498         /* check for patches with adjacent edges that need to lod together */
499         PatchMapDrawSurfs( e );
500         
501         /* allocate a tree */
502         node = AllocNode();
503         node->planenum = PLANENUM_LEAF;
504         tree = AllocTree();
505         tree->headnode = node;
506         
507         /* add the sides to the tree */
508         ClipSidesIntoTree( e, tree );
509         
510         /* ydnar: create drawsurfs for triangle models */
511         AddTriangleModels( e );
512         
513         /* create drawsurfs for surface models */
514         AddEntitySurfaceModels( e );
515         
516         /* generate bsp brushes from map brushes */
517         EmitBrushes( e->brushes, &e->firstBrush, &e->numBrushes );
518
519         /* just put all the brushes in headnode */
520         for( b = e->brushes; b; b = b->next )
521         {
522                 bc = CopyBrush( b );
523                 bc->next = node->brushlist;
524                 node->brushlist = bc;
525         }
526         
527         /* subdivide each drawsurf as required by shader tesselation */
528         if( !nosubdivide )
529                 SubdivideFaceSurfaces( e, tree );
530         
531         /* add in any vertexes required to fix t-junctions */
532         if( !notjunc )
533                 FixTJunctions( e );
534         
535         /* ydnar: classify the surfaces and project lightmaps */
536         ClassifyEntitySurfaces( e );
537         
538         /* ydnar: project decals */
539         MakeEntityDecals( e );
540         
541         /* ydnar: meta surfaces */
542         MakeEntityMetaTriangles( e );
543         SmoothMetaTriangles();
544         FixMetaTJunctions();
545         MergeMetaTriangles();
546         
547         /* add references to the final drawsurfs in the apropriate clusters */
548         FilterDrawsurfsIntoTree( e, tree );
549         
550         /* match drawsurfaces back to original brushsides (sof2) */
551         FixBrushSides( e );
552         
553         /* finish */
554         EndModel( e, node );
555         FreeTree( tree );
556 }
557
558
559
560 /*
561 ProcessModels()
562 process world + other models into the bsp
563 */
564
565 void ProcessModels( void )
566 {
567         qboolean        oldVerbose;
568         entity_t        *entity;
569         
570         
571         /* preserve -v setting */
572         oldVerbose = verbose;
573         
574         /* start a new bsp */
575         BeginBSPFile();
576         
577         /* create map fogs */
578         CreateMapFogs();
579         
580         /* walk entity list */
581         for( mapEntityNum = 0; mapEntityNum < numEntities; mapEntityNum++ )
582         {
583                 /* get entity */
584                 entity = &entities[ mapEntityNum ];
585                 if( entity->brushes == NULL && entity->patches == NULL )
586                         continue;
587                 
588                 /* process the model */
589                 Sys_FPrintf( SYS_VRB, "############### model %i ###############\n", numBSPModels );
590                 if( mapEntityNum == 0 )
591                         ProcessWorldModel();
592                 else
593                         ProcessSubModel();
594                 
595                 /* potentially turn off the deluge of text */
596                 verbose = verboseEntities;
597         }
598         
599         /* restore -v setting */
600         verbose = oldVerbose;
601         
602         /* write fogs */
603         EmitFogs();
604 }
605
606
607
608 /*
609 OnlyEnts()
610 this is probably broken unless teamed with a radiant version that preserves entity order
611 */
612
613 void OnlyEnts( void )
614 {
615         char out[ 1024 ];
616
617         char save_cmdline[1024], save_version[1024];
618         const char *p;
619         
620         /* note it */
621         Sys_Printf( "--- OnlyEnts ---\n" );
622         
623         sprintf( out, "%s.bsp", source );
624         LoadBSPFile( out );
625
626         ParseEntities();
627         p = ValueForKey(&entities[0], "_q3map2_cmdline");
628         strncpy(save_cmdline, p, sizeof(save_cmdline));
629         save_cmdline[sizeof(save_cmdline)-1] = 0;
630         p = ValueForKey(&entities[0], "_q3map2_version");
631         strncpy(save_version, p, sizeof(save_version));
632         save_version[sizeof(save_version)-1] = 0;
633
634         numEntities = 0;
635
636         LoadShaderInfo();
637         LoadMapFile( name, qfalse );
638         SetModelNumbers();
639         SetLightStyles();
640
641         if(*save_cmdline)
642                 SetKeyValue(&entities[0], "_q3map2_cmdline", save_cmdline);
643         if(*save_version)
644                 SetKeyValue(&entities[0], "_q3map2_version", save_version);
645         
646         numBSPEntities = numEntities;
647         UnparseEntities();
648         
649         WriteBSPFile( out );
650 }
651
652
653
654 /*
655 BSPMain() - ydnar
656 handles creation of a bsp from a map file
657 */
658
659 int BSPMain( int argc, char **argv )
660 {
661         int                     i;
662         char            path[ 1024 ], tempSource[ 1024 ];
663         qboolean        onlyents = qfalse;
664         
665         
666         /* note it */
667         Sys_Printf( "--- BSP ---\n" );
668         
669         SetDrawSurfacesBuffer();
670         mapDrawSurfs = safe_malloc( sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS );
671         memset( mapDrawSurfs, 0, sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS );
672         numMapDrawSurfs = 0;
673         
674         tempSource[ 0 ] = '\0';
675         
676         /* set standard game flags */
677         maxSurfaceVerts = game->maxSurfaceVerts;
678         maxSurfaceIndexes = game->maxSurfaceIndexes;
679         emitFlares = game->emitFlares;
680         
681         /* process arguments */
682         for( i = 1; i < (argc - 1); i++ )
683         {
684                 if( !strcmp( argv[ i ], "-onlyents" ) )
685                 {
686                         Sys_Printf( "Running entity-only compile\n" );
687                         onlyents = qtrue;
688                 }
689                 else if( !strcmp( argv[ i ], "-tempname" ) )
690                         strcpy( tempSource, argv[ ++i ] );
691                 else if( !strcmp( argv[ i ], "-tmpout" ) )
692                         strcpy( outbase, "/tmp" );
693                 else if( !strcmp( argv[ i ],  "-nowater" ) )
694                 {
695                         Sys_Printf( "Disabling water\n" );
696                         nowater = qtrue;
697                 }
698                 else if( !strcmp( argv[ i ],  "-nodetail" ) )
699                 {
700                         Sys_Printf( "Ignoring detail brushes\n") ;
701                         nodetail = qtrue;
702                 }
703                 else if( !strcmp( argv[ i ],  "-fulldetail" ) )
704                 {
705                         Sys_Printf( "Turning detail brushes into structural brushes\n" );
706                         fulldetail = qtrue;
707                 }
708                 else if( !strcmp( argv[ i ],  "-nofog" ) )
709                 {
710                         Sys_Printf( "Fog volumes disabled\n" );
711                         nofog = qtrue;
712                 }
713                 else if( !strcmp( argv[ i ],  "-nosubdivide" ) )
714                 {
715                         Sys_Printf( "Disabling brush face subdivision\n" );
716                         nosubdivide = qtrue;
717                 }
718                 else if( !strcmp( argv[ i ],  "-leaktest" ) )
719                 {
720                         Sys_Printf( "Leaktest enabled\n" );
721                         leaktest = qtrue;
722                 }
723                 else if( !strcmp( argv[ i ],  "-verboseentities" ) )
724                 {
725                         Sys_Printf( "Verbose entities enabled\n" );
726                         verboseEntities = qtrue;
727                 }
728                 else if( !strcmp( argv[ i ], "-nocurves" ) )
729                 {
730                         Sys_Printf( "Ignoring curved surfaces (patches)\n" );
731                         noCurveBrushes = qtrue;
732                 }
733                 else if( !strcmp( argv[ i ], "-notjunc" ) )
734                 {
735                         Sys_Printf( "T-junction fixing disabled\n" );
736                         notjunc = qtrue;
737                 }
738                 else if( !strcmp( argv[ i ], "-fakemap" ) )
739                 {
740                         Sys_Printf( "Generating fakemap.map\n" );
741                         fakemap = qtrue;
742                 }
743                 else if( !strcmp( argv[ i ],  "-samplesize" ) )
744                 {
745                         sampleSize = atoi( argv[ i + 1 ] );
746                         if( sampleSize < 1 )
747                                 sampleSize = 1;
748                         i++;
749                         Sys_Printf( "Lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
750                 }
751                 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
752                 {
753                         minSampleSize = atoi( argv[ i + 1 ] );
754                         if( minSampleSize < 1 )
755                                 minSampleSize = 1;
756                         i++;
757                         Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
758                 }
759                 else if( !strcmp( argv[ i ],  "-custinfoparms") )
760                 {
761                         Sys_Printf( "Custom info parms enabled\n" );
762                         useCustomInfoParms = qtrue;
763                 }
764                 
765                 /* sof2 args */
766                 else if( !strcmp( argv[ i ], "-rename" ) )
767                 {
768                         Sys_Printf( "Appending _bsp suffix to misc_model shaders (SOF2)\n" );
769                         renameModelShaders = qtrue;
770                 }
771                 
772                 /* ydnar args */
773                 else if( !strcmp( argv[ i ],  "-ne" ) )
774                 {
775                         normalEpsilon = atof( argv[ i + 1 ] );
776                         i++;
777                         Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
778                 }
779                 else if( !strcmp( argv[ i ],  "-de" ) )
780                 {
781                         distanceEpsilon = atof( argv[ i + 1 ] );
782                         i++;
783                         Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
784                 }
785                 else if( !strcmp( argv[ i ],  "-mv" ) )
786                 {
787                         maxLMSurfaceVerts = atoi( argv[ i + 1 ] );
788                         if( maxLMSurfaceVerts < 3 )
789                                 maxLMSurfaceVerts = 3;
790                         if( maxLMSurfaceVerts > maxSurfaceVerts )
791                                 maxSurfaceVerts = maxLMSurfaceVerts;
792                         i++;
793                         Sys_Printf( "Maximum lightmapped surface vertex count set to %d\n", maxLMSurfaceVerts );
794                 }
795                 else if( !strcmp( argv[ i ],  "-mi" ) )
796                 {
797                         maxSurfaceIndexes = atoi( argv[ i + 1 ] );
798                         if( maxSurfaceIndexes < 3 )
799                                 maxSurfaceIndexes = 3;
800                         i++;
801                         Sys_Printf( "Maximum per-surface index count set to %d\n", maxSurfaceIndexes );
802                 }
803                 else if( !strcmp( argv[ i ], "-np" ) )
804                 {
805                         npDegrees = atof( argv[ i + 1 ] );
806                         if( npDegrees < 0.0f )
807                                 shadeAngleDegrees = 0.0f;
808                         else if( npDegrees > 0.0f )
809                                 Sys_Printf( "Forcing nonplanar surfaces with a breaking angle of %f degrees\n", npDegrees );
810                         i++;
811                 }
812                 else if( !strcmp( argv[ i ],  "-snap" ) )
813                 {
814                         bevelSnap = atoi( argv[ i + 1 ]);
815                         if( bevelSnap < 0 )
816                                 bevelSnap = 0;
817                         i++;
818                         if( bevelSnap > 0 )
819                                 Sys_Printf( "Snapping brush bevel planes to %d units\n", bevelSnap );
820                 }
821                 else if( !strcmp( argv[ i ],  "-texrange" ) )
822                 {
823                         texRange = atoi( argv[ i + 1 ]);
824                         if( texRange < 0 )
825                                 texRange = 0;
826                         i++;
827                         Sys_Printf( "Limiting per-surface texture range to %d texels\n", texRange );
828                 }
829                 else if( !strcmp( argv[ i ], "-nohint" ) )
830                 {
831                         Sys_Printf( "Hint brushes disabled\n" );
832                         noHint = qtrue;
833                 }
834                 else if( !strcmp( argv[ i ], "-flat" ) )
835                 {
836                         Sys_Printf( "Flatshading enabled\n" );
837                         flat = qtrue;
838                 }
839                 else if( !strcmp( argv[ i ], "-meta" ) )
840                 {
841                         Sys_Printf( "Creating meta surfaces from brush faces\n" );
842                         meta = qtrue;
843                 }
844                 else if( !strcmp( argv[ i ], "-patchmeta" ) )
845                 {
846                         Sys_Printf( "Creating meta surfaces from patches\n" );
847                         patchMeta = qtrue;
848                 }
849                 else if( !strcmp( argv[ i ], "-flares" ) )
850                 {
851                         Sys_Printf( "Flare surfaces enabled\n" );
852                         emitFlares = qtrue;
853                 }
854                 else if( !strcmp( argv[ i ], "-noflares" ) )
855                 {
856                         Sys_Printf( "Flare surfaces disabled\n" );
857                         emitFlares = qfalse;
858                 }
859                 else if( !strcmp( argv[ i ], "-skyfix" ) )
860                 {
861                         Sys_Printf( "GL_CLAMP sky fix/hack/workaround enabled\n" );
862                         skyFixHack = qtrue;
863                 }
864                 else if( !strcmp( argv[ i ], "-debugsurfaces" ) )
865                 {
866                         Sys_Printf( "emitting debug surfaces\n" );
867                         debugSurfaces = qtrue;
868                 }
869                 else if( !strcmp( argv[ i ], "-debuginset" ) )
870                 {
871                         Sys_Printf( "Debug surface triangle insetting enabled\n" );
872                         debugInset = qtrue;
873                 }
874                 else if( !strcmp( argv[ i ], "-debugportals" ) )
875                 {
876                         Sys_Printf( "Debug portal surfaces enabled\n" );
877                         debugPortals = qtrue;
878                 }
879                 else if( !strcmp( argv[ i ], "-bsp" ) )
880                         Sys_Printf( "-bsp argument unnecessary\n" );
881                 else
882                 {
883                         Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );
884                 }
885         }
886         
887         /* fixme: print more useful usage here */
888         if( i != (argc - 1) )
889                 Error( "usage: q3map [options] mapfile" );
890         
891         /* copy source name */
892         strcpy( source, ExpandArg( argv[ i ] ) );
893         StripExtension( source );
894         
895         /* ydnar: set default sample size */
896         SetDefaultSampleSize( sampleSize );
897         
898         /* delete portal, line and surface files */
899         sprintf( path, "%s.prt", source );
900         remove( path );
901         sprintf( path, "%s.lin", source );
902         remove( path );
903         //%     sprintf( path, "%s.srf", source );      /* ydnar */
904         //%     remove( path );
905         
906         /* expand mapname */
907         strcpy( name, ExpandArg( argv[ i ] ) ); 
908         if( strcmp( name + strlen( name ) - 4, ".reg" ) )
909         {
910                 /* if we are doing a full map, delete the last saved region map */
911                 sprintf( path, "%s.reg", source );
912                 remove( path );
913                 DefaultExtension( name, ".map" );       /* might be .reg */
914         }
915         
916         /* if onlyents, just grab the entites and resave */
917         if( onlyents )
918         {
919                 OnlyEnts();
920                 return 0;
921         }
922         
923         /* load shaders */
924         LoadShaderInfo();
925         
926         /* load original file from temp spot in case it was renamed by the editor on the way in */
927         if( strlen( tempSource ) > 0 )
928                 LoadMapFile( tempSource, qfalse );
929         else
930                 LoadMapFile( name, qfalse );
931         
932         /* div0: inject command line parameters */
933         InjectCommandLine(argv, 1, argc - 1);
934         
935         /* ydnar: decal setup */
936         ProcessDecals();
937         
938         /* ydnar: cloned brush model entities */
939         SetCloneModelNumbers();
940         
941         /* process world and submodels */
942         ProcessModels();
943         
944         /* set light styles from targetted light entities */
945         SetLightStyles();
946         
947         /* process in game advertisements */
948         ProcessAdvertisements();
949
950         /* finish and write bsp */
951         EndBSPFile();
952         
953         /* remove temp map source file if appropriate */
954         if( strlen( tempSource ) > 0)
955                 remove( tempSource );
956         
957         /* return to sender */
958         return 0;
959 }
960