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