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