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