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