some stuff by 27:
[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         /* sets integer blockSize from worldspawn "_blocksize" key if it exists */
268         value = ValueForKey( &entities[ 0 ], "_blocksize" );
269         if( value[ 0 ] == '\0' )
270                 value = ValueForKey( &entities[ 0 ], "blocksize" );
271         if( value[ 0 ] == '\0' )
272                 value = ValueForKey( &entities[ 0 ], "chopsize" );      /* sof2 */
273         if( value[ 0 ] != '\0' )
274         {
275                 /* scan 3 numbers */
276                 s = sscanf( value, "%d %d %d", &blockSize[ 0 ], &blockSize[ 1 ], &blockSize[ 2 ] );
277                 
278                 /* handle legacy case */
279                 if( s == 1 )
280                 {
281                         blockSize[ 1 ] = blockSize[ 0 ];
282                         blockSize[ 2 ] = blockSize[ 0 ];
283                 }
284         }
285         Sys_Printf( "block size = { %d %d %d }\n", blockSize[ 0 ], blockSize[ 1 ], blockSize[ 2 ] );
286         
287         /* sof2: ignore leaks? */
288         value = ValueForKey( &entities[ 0 ], "_ignoreleaks" );  /* ydnar */
289         if( value[ 0 ] == '\0' )
290                 value = ValueForKey( &entities[ 0 ], "ignoreleaks" );
291         if( value[ 0 ] == '1' )
292                 ignoreLeaks = qtrue;
293         else
294                 ignoreLeaks = qfalse;
295         
296         /* begin worldspawn model */
297         BeginModel();
298         e = &entities[ 0 ];
299         e->firstDrawSurf = 0;
300         
301         /* ydnar: gs mods */
302         ClearMetaTriangles();
303
304         /* check for patches with adjacent edges that need to lod together */
305         PatchMapDrawSurfs( e );
306
307         /* build an initial bsp tree using all of the sides of all of the structural brushes */
308         faces = MakeStructuralBSPFaceList( entities[ 0 ].brushes );
309         tree = FaceBSP( faces );
310         MakeTreePortals( tree );
311         FilterStructuralBrushesIntoTree( e, tree );
312         
313         /* see if the bsp is completely enclosed */
314         if( FloodEntities( tree ) || ignoreLeaks )
315         {
316                 /* rebuild a better bsp tree using only the sides that are visible from the inside */
317                 FillOutside( tree->headnode );
318
319                 /* chop the sides to the convex hull of their visible fragments, giving us the smallest polygons */
320                 ClipSidesIntoTree( e, tree );
321                 
322                 /* build a visible face tree */
323                 faces = MakeVisibleBSPFaceList( entities[ 0 ].brushes );
324                 FreeTree( tree );
325                 tree = FaceBSP( faces );
326                 MakeTreePortals( tree );
327                 FilterStructuralBrushesIntoTree( e, tree );
328                 leaked = qfalse;
329                 
330                 /* ydnar: flood again for skybox */
331                 if( skyboxPresent )
332                         FloodEntities( tree );
333         }
334         else
335         {
336                 Sys_FPrintf( SYS_NOXML, "**********************\n" );
337                 Sys_FPrintf( SYS_NOXML, "******* leaked *******\n" );
338                 Sys_FPrintf( SYS_NOXML, "**********************\n" );
339                 polyline = LeakFile( tree );
340                 leaknode = xmlNewNode( NULL, "message" );
341                 xmlNodeSetContent( leaknode, "MAP LEAKED\n" );
342                 xmlAddChild( leaknode, polyline );
343                 level[0] = (int) '0' + SYS_ERR;
344                 level[1] = 0;
345                 xmlSetProp( leaknode, "level", (char*) &level );
346                 xml_SendNode( leaknode );
347                 if( leaktest )
348                 {
349                         Sys_Printf ("--- MAP LEAKED, ABORTING LEAKTEST ---\n");
350                         exit( 0 );
351                 }
352                 leaked = qtrue;
353                 
354                 /* chop the sides to the convex hull of their visible fragments, giving us the smallest polygons */
355                 ClipSidesIntoTree( e, tree );
356         }
357         
358         /* save out information for visibility processing */
359         NumberClusters( tree );
360         if( !leaked )
361                 WritePortalFile( tree );
362         
363         /* flood from entities */
364         FloodAreas( tree );
365         
366         /* create drawsurfs for triangle models */
367         AddTriangleModels( e );
368         
369         /* create drawsurfs for surface models */
370         AddEntitySurfaceModels( e );
371         
372         /* generate bsp brushes from map brushes */
373         EmitBrushes( e->brushes, &e->firstBrush, &e->numBrushes );
374         
375         /* add references to the detail brushes */
376         FilterDetailBrushesIntoTree( e, tree );
377         
378         /* drawsurfs that cross fog boundaries will need to be split along the fog boundary */
379         if( !nofog )
380                 FogDrawSurfaces( e );
381         
382         /* subdivide each drawsurf as required by shader tesselation */
383         if( !nosubdivide )
384                 SubdivideFaceSurfaces( e, tree );
385         
386         /* add in any vertexes required to fix t-junctions */
387         if( !notjunc )
388                 FixTJunctions( e );
389         
390         /* ydnar: classify the surfaces */
391         ClassifyEntitySurfaces( e );
392         
393         /* ydnar: project decals */
394         MakeEntityDecals( e );
395         
396         /* ydnar: meta surfaces */
397         MakeEntityMetaTriangles( e );
398         SmoothMetaTriangles();
399         FixMetaTJunctions();
400         MergeMetaTriangles();
401         
402         /* ydnar: debug portals */
403         if( debugPortals )
404                 MakeDebugPortalSurfs( tree );
405         
406         /* ydnar: fog hull */
407         value = ValueForKey( &entities[ 0 ], "_foghull" );
408         if( value[ 0 ] != '\0' )
409         {
410                 sprintf( shader, "textures/%s", value );
411                 MakeFogHullSurfs( e, tree, shader );
412         }
413         
414         /* ydnar: bug 645: do flares for lights */
415         for( i = 0; i < numEntities && emitFlares; i++ )
416         {
417                 entity_t        *light, *target;
418                 const char      *value, *flareShader;
419                 vec3_t          origin, targetOrigin, normal, color;
420                 int                     lightStyle;
421                 
422                 
423                 /* get light */
424                 light = &entities[ i ];
425                 value = ValueForKey( light, "classname" );
426                 if( !strcmp( value, "light" ) )
427                 {
428                         /* get flare shader */
429                         flareShader = ValueForKey( light, "_flareshader" );
430                         value = ValueForKey( light, "_flare" );
431                         if( flareShader[ 0 ] != '\0' || value[ 0 ] != '\0' )
432                         {
433                                 /* get specifics */
434                                 GetVectorForKey( light, "origin", origin );
435                                 GetVectorForKey( light, "_color", color );
436                                 lightStyle = IntForKey( light, "_style" );
437                                 if( lightStyle == 0 )
438                                         lightStyle = IntForKey( light, "style" );
439                                 
440                                 /* handle directional spotlights */
441                                 value = ValueForKey( light, "target" );
442                                 if( value[ 0 ] != '\0' )
443                                 {
444                                         /* get target light */
445                                         target = FindTargetEntity( value );
446                                         if( target != NULL )
447                                         {
448                                                 GetVectorForKey( target, "origin", targetOrigin );
449                                                 VectorSubtract( targetOrigin, origin, normal );
450                                                 VectorNormalize( normal, normal );
451                                         }
452                                 }
453                                 else
454                                         //%     VectorClear( normal );
455                                         VectorSet( normal, 0, 0, -1 );
456                                 
457                                 /* create the flare surface (note shader defaults automatically) */
458                                 DrawSurfaceForFlare( mapEntityNum, origin, normal, color, (char*) flareShader, lightStyle );
459                         }
460                 }
461         }
462         
463         /* add references to the final drawsurfs in the apropriate clusters */
464         FilterDrawsurfsIntoTree( e, tree );
465         
466         /* match drawsurfaces back to original brushsides (sof2) */
467         FixBrushSides( e );
468         
469         /* finish */
470         EndModel( e, tree->headnode );
471         FreeTree( tree );
472 }
473
474
475
476 /*
477 ProcessSubModel()
478 creates bsp + surfaces for other brush models
479 */
480
481 void ProcessSubModel( void )
482 {
483         entity_t        *e;
484         tree_t          *tree;
485         brush_t         *b, *bc;
486         node_t          *node;
487         
488         
489         /* start a brush model */
490         BeginModel();
491         e = &entities[ mapEntityNum ];
492         e->firstDrawSurf = numMapDrawSurfs;
493         
494         /* ydnar: gs mods */
495         ClearMetaTriangles();
496         
497         /* check for patches with adjacent edges that need to lod together */
498         PatchMapDrawSurfs( e );
499         
500         /* allocate a tree */
501         node = AllocNode();
502         node->planenum = PLANENUM_LEAF;
503         tree = AllocTree();
504         tree->headnode = node;
505         
506         /* add the sides to the tree */
507         ClipSidesIntoTree( e, tree );
508         
509         /* ydnar: create drawsurfs for triangle models */
510         AddTriangleModels( e );
511         
512         /* create drawsurfs for surface models */
513         AddEntitySurfaceModels( e );
514         
515         /* generate bsp brushes from map brushes */
516         EmitBrushes( e->brushes, &e->firstBrush, &e->numBrushes );
517
518         /* just put all the brushes in headnode */
519         for( b = e->brushes; b; b = b->next )
520         {
521                 bc = CopyBrush( b );
522                 bc->next = node->brushlist;
523                 node->brushlist = bc;
524         }
525         
526         /* subdivide each drawsurf as required by shader tesselation */
527         if( !nosubdivide )
528                 SubdivideFaceSurfaces( e, tree );
529         
530         /* add in any vertexes required to fix t-junctions */
531         if( !notjunc )
532                 FixTJunctions( e );
533         
534         /* ydnar: classify the surfaces and project lightmaps */
535         ClassifyEntitySurfaces( e );
536         
537         /* ydnar: project decals */
538         MakeEntityDecals( e );
539         
540         /* ydnar: meta surfaces */
541         MakeEntityMetaTriangles( e );
542         SmoothMetaTriangles();
543         FixMetaTJunctions();
544         MergeMetaTriangles();
545         
546         /* add references to the final drawsurfs in the apropriate clusters */
547         FilterDrawsurfsIntoTree( e, tree );
548         
549         /* match drawsurfaces back to original brushsides (sof2) */
550         FixBrushSides( e );
551         
552         /* finish */
553         EndModel( e, node );
554         FreeTree( tree );
555 }
556
557
558
559 /*
560 ProcessModels()
561 process world + other models into the bsp
562 */
563
564 void ProcessModels( void )
565 {
566         qboolean        oldVerbose;
567         entity_t        *entity;
568         
569         
570         /* preserve -v setting */
571         oldVerbose = verbose;
572         
573         /* start a new bsp */
574         BeginBSPFile();
575         
576         /* create map fogs */
577         CreateMapFogs();
578         
579         /* walk entity list */
580         for( mapEntityNum = 0; mapEntityNum < numEntities; mapEntityNum++ )
581         {
582                 /* get entity */
583                 entity = &entities[ mapEntityNum ];
584                 if( entity->brushes == NULL && entity->patches == NULL )
585                         continue;
586                 
587                 /* process the model */
588                 Sys_FPrintf( SYS_VRB, "############### model %i ###############\n", numBSPModels );
589                 if( mapEntityNum == 0 )
590                         ProcessWorldModel();
591                 else
592                         ProcessSubModel();
593                 
594                 /* potentially turn off the deluge of text */
595                 verbose = verboseEntities;
596         }
597         
598         /* restore -v setting */
599         verbose = oldVerbose;
600         
601         /* write fogs */
602         EmitFogs();
603
604         /* vortex: emit meta stats */
605         EmitMetaStats();
606 }
607
608
609
610 /*
611 OnlyEnts()
612 this is probably broken unless teamed with a radiant version that preserves entity order
613 */
614
615 void OnlyEnts( void )
616 {
617         char out[ 1024 ];
618
619         char save_cmdline[1024], save_version[1024];
620         const char *p;
621         
622         /* note it */
623         Sys_Printf( "--- OnlyEnts ---\n" );
624         
625         sprintf( out, "%s.bsp", source );
626         LoadBSPFile( out );
627
628         ParseEntities();
629         p = ValueForKey(&entities[0], "_q3map2_cmdline");
630         strncpy(save_cmdline, p, sizeof(save_cmdline));
631         save_cmdline[sizeof(save_cmdline)-1] = 0;
632         p = ValueForKey(&entities[0], "_q3map2_version");
633         strncpy(save_version, p, sizeof(save_version));
634         save_version[sizeof(save_version)-1] = 0;
635
636         numEntities = 0;
637
638         LoadShaderInfo();
639         LoadMapFile( name, qfalse );
640         SetModelNumbers();
641         SetLightStyles();
642
643         if(*save_cmdline)
644                 SetKeyValue(&entities[0], "_q3map2_cmdline", save_cmdline);
645         if(*save_version)
646                 SetKeyValue(&entities[0], "_q3map2_version", save_version);
647         
648         numBSPEntities = numEntities;
649         UnparseEntities();
650         
651         WriteBSPFile( out );
652 }
653
654
655
656 /*
657 BSPMain() - ydnar
658 handles creation of a bsp from a map file
659 */
660
661 int BSPMain( int argc, char **argv )
662 {
663         int                     i;
664         char            path[ 1024 ], tempSource[ 1024 ];
665         qboolean        onlyents = qfalse;
666         
667         
668         /* note it */
669         Sys_Printf( "--- BSP ---\n" );
670         
671         SetDrawSurfacesBuffer();
672         mapDrawSurfs = safe_malloc( sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS );
673         memset( mapDrawSurfs, 0, sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS );
674         numMapDrawSurfs = 0;
675         
676         tempSource[ 0 ] = '\0';
677         globalCelShader[0] = 0;
678         
679         /* set standard game flags */
680         maxSurfaceVerts = game->maxSurfaceVerts;
681         maxSurfaceIndexes = game->maxSurfaceIndexes;
682         emitFlares = game->emitFlares;
683         
684         /* process arguments */
685         for( i = 1; i < (argc - 1); i++ )
686         {
687                 if( !strcmp( argv[ i ], "-onlyents" ) )
688                 {
689                         Sys_Printf( "Running entity-only compile\n" );
690                         onlyents = qtrue;
691                 }
692                 else if( !strcmp( argv[ i ], "-tempname" ) )
693                         strcpy( tempSource, argv[ ++i ] );
694                 else if( !strcmp( argv[ i ], "-tmpout" ) )
695                         strcpy( outbase, "/tmp" );
696                 else if( !strcmp( argv[ i ],  "-nowater" ) )
697                 {
698                         Sys_Printf( "Disabling water\n" );
699                         nowater = qtrue;
700                 }
701                 else if( !strcmp( argv[ i ],  "-nodetail" ) )
702                 {
703                         Sys_Printf( "Ignoring detail brushes\n") ;
704                         nodetail = qtrue;
705                 }
706                 else if( !strcmp( argv[ i ],  "-fulldetail" ) )
707                 {
708                         Sys_Printf( "Turning detail brushes into structural brushes\n" );
709                         fulldetail = qtrue;
710                 }
711                 else if( !strcmp( argv[ i ],  "-nofog" ) )
712                 {
713                         Sys_Printf( "Fog volumes disabled\n" );
714                         nofog = qtrue;
715                 }
716                 else if( !strcmp( argv[ i ],  "-nosubdivide" ) )
717                 {
718                         Sys_Printf( "Disabling brush face subdivision\n" );
719                         nosubdivide = qtrue;
720                 }
721                 else if( !strcmp( argv[ i ],  "-leaktest" ) )
722                 {
723                         Sys_Printf( "Leaktest enabled\n" );
724                         leaktest = qtrue;
725                 }
726                 else if( !strcmp( argv[ i ],  "-verboseentities" ) )
727                 {
728                         Sys_Printf( "Verbose entities enabled\n" );
729                         verboseEntities = qtrue;
730                 }
731                 else if( !strcmp( argv[ i ], "-nocurves" ) )
732                 {
733                         Sys_Printf( "Ignoring curved surfaces (patches)\n" );
734                         noCurveBrushes = qtrue;
735                 }
736                 else if( !strcmp( argv[ i ], "-notjunc" ) )
737                 {
738                         Sys_Printf( "T-junction fixing disabled\n" );
739                         notjunc = qtrue;
740                 }
741                 else if( !strcmp( argv[ i ], "-fakemap" ) )
742                 {
743                         Sys_Printf( "Generating fakemap.map\n" );
744                         fakemap = qtrue;
745                 }
746                 else if( !strcmp( argv[ i ],  "-samplesize" ) )
747                 {
748                         sampleSize = atoi( argv[ i + 1 ] );
749                         if( sampleSize < 1 )
750                                 sampleSize = 1;
751                         i++;
752                         Sys_Printf( "Lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
753                 }
754                 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
755                 {
756                         minSampleSize = atoi( argv[ i + 1 ] );
757                         if( minSampleSize < 1 )
758                                 minSampleSize = 1;
759                         i++;
760                         Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
761                 }
762                 else if( !strcmp( argv[ i ],  "-custinfoparms") )
763                 {
764                         Sys_Printf( "Custom info parms enabled\n" );
765                         useCustomInfoParms = qtrue;
766                 }
767                 
768                 /* sof2 args */
769                 else if( !strcmp( argv[ i ], "-rename" ) )
770                 {
771                         Sys_Printf( "Appending _bsp suffix to misc_model shaders (SOF2)\n" );
772                         renameModelShaders = qtrue;
773                 }
774                 
775                 /* ydnar args */
776                 else if( !strcmp( argv[ i ],  "-ne" ) )
777                 {
778                         normalEpsilon = atof( argv[ i + 1 ] );
779                         i++;
780                         Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
781                 }
782                 else if( !strcmp( argv[ i ],  "-de" ) )
783                 {
784                         distanceEpsilon = atof( argv[ i + 1 ] );
785                         i++;
786                         Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
787                 }
788                 else if( !strcmp( argv[ i ],  "-mv" ) )
789                 {
790                         maxLMSurfaceVerts = atoi( argv[ i + 1 ] );
791                         if( maxLMSurfaceVerts < 3 )
792                                 maxLMSurfaceVerts = 3;
793                         if( maxLMSurfaceVerts > maxSurfaceVerts )
794                                 maxSurfaceVerts = maxLMSurfaceVerts;
795                         i++;
796                         Sys_Printf( "Maximum lightmapped surface vertex count set to %d\n", maxLMSurfaceVerts );
797                 }
798                 else if( !strcmp( argv[ i ],  "-mi" ) )
799                 {
800                         maxSurfaceIndexes = atoi( argv[ i + 1 ] );
801                         if( maxSurfaceIndexes < 3 )
802                                 maxSurfaceIndexes = 3;
803                         i++;
804                         Sys_Printf( "Maximum per-surface index count set to %d\n", maxSurfaceIndexes );
805                 }
806                 else if( !strcmp( argv[ i ], "-np" ) )
807                 {
808                         npDegrees = atof( argv[ i + 1 ] );
809                         if( npDegrees < 0.0f )
810                                 shadeAngleDegrees = 0.0f;
811                         else if( npDegrees > 0.0f )
812                                 Sys_Printf( "Forcing nonplanar surfaces with a breaking angle of %f degrees\n", npDegrees );
813                         i++;
814                 }
815                 else if( !strcmp( argv[ i ],  "-snap" ) )
816                 {
817                         bevelSnap = atoi( argv[ i + 1 ]);
818                         if( bevelSnap < 0 )
819                                 bevelSnap = 0;
820                         i++;
821                         if( bevelSnap > 0 )
822                                 Sys_Printf( "Snapping brush bevel planes to %d units\n", bevelSnap );
823                 }
824                 else if( !strcmp( argv[ i ],  "-texrange" ) )
825                 {
826                         texRange = atoi( argv[ i + 1 ]);
827                         if( texRange < 0 )
828                                 texRange = 0;
829                         i++;
830                         Sys_Printf( "Limiting per-surface texture range to %d texels\n", texRange );
831                 }
832                 else if( !strcmp( argv[ i ], "-nohint" ) )
833                 {
834                         Sys_Printf( "Hint brushes disabled\n" );
835                         noHint = qtrue;
836                 }
837                 else if( !strcmp( argv[ i ], "-flat" ) )
838                 {
839                         Sys_Printf( "Flatshading enabled\n" );
840                         flat = qtrue;
841                 }
842                 else if( !strcmp( argv[ i ], "-celshader" ) )
843                 {
844                         ++i;
845                         if(argv[i][0])
846                                 sprintf( globalCelShader, "textures/%s", argv[ i ] );
847                         else
848                                 *globalCelShader = 0;
849                         Sys_Printf( "Global cel shader set to \"%s\"\n", globalCelShader );
850                 }
851                 else if( !strcmp( argv[ i ], "-meta" ) )
852                 {
853                         Sys_Printf( "Creating meta surfaces from brush faces\n" );
854                         meta = qtrue;
855                 }
856                 else if( !strcmp( argv[ i ], "-patchmeta" ) )
857                 {
858                         Sys_Printf( "Creating meta surfaces from patches\n" );
859                         patchMeta = qtrue;
860                 }
861                 else if( !strcmp( argv[ i ], "-flares" ) )
862                 {
863                         Sys_Printf( "Flare surfaces enabled\n" );
864                         emitFlares = qtrue;
865                 }
866                 else if( !strcmp( argv[ i ], "-noflares" ) )
867                 {
868                         Sys_Printf( "Flare surfaces disabled\n" );
869                         emitFlares = qfalse;
870                 }
871                 else if( !strcmp( argv[ i ], "-skyfix" ) )
872                 {
873                         Sys_Printf( "GL_CLAMP sky fix/hack/workaround enabled\n" );
874                         skyFixHack = qtrue;
875                 }
876                 else if( !strcmp( argv[ i ], "-debugsurfaces" ) )
877                 {
878                         Sys_Printf( "emitting debug surfaces\n" );
879                         debugSurfaces = qtrue;
880                 }
881                 else if( !strcmp( argv[ i ], "-debuginset" ) )
882                 {
883                         Sys_Printf( "Debug surface triangle insetting enabled\n" );
884                         debugInset = qtrue;
885                 }
886                 else if( !strcmp( argv[ i ], "-debugportals" ) )
887                 {
888                         Sys_Printf( "Debug portal surfaces enabled\n" );
889                         debugPortals = qtrue;
890                 }
891                 else if( !strcmp( argv[ i ], "-altsplit" ) )
892                 {
893                         Sys_Printf( "Alternate BSP splitting (by 27) enabled\n" );
894                         bspAlternateSplitWeights = qtrue;
895                 }
896                 else if( !strcmp( argv[ i ], "-bsp" ) )
897                         Sys_Printf( "-bsp argument unnecessary\n" );
898                 else
899                 {
900                         Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );
901                 }
902         }
903         
904         /* fixme: print more useful usage here */
905         if( i != (argc - 1) )
906                 Error( "usage: q3map [options] mapfile" );
907         
908         /* copy source name */
909         strcpy( source, ExpandArg( argv[ i ] ) );
910         StripExtension( source );
911         
912         /* ydnar: set default sample size */
913         SetDefaultSampleSize( sampleSize );
914         
915         /* delete portal, line and surface files */
916         sprintf( path, "%s.prt", source );
917         remove( path );
918         sprintf( path, "%s.lin", source );
919         remove( path );
920         //%     sprintf( path, "%s.srf", source );      /* ydnar */
921         //%     remove( path );
922         
923         /* expand mapname */
924         strcpy( name, ExpandArg( argv[ i ] ) ); 
925         if( strcmp( name + strlen( name ) - 4, ".reg" ) )
926         {
927                 /* if we are doing a full map, delete the last saved region map */
928                 sprintf( path, "%s.reg", source );
929                 remove( path );
930                 DefaultExtension( name, ".map" );       /* might be .reg */
931         }
932         
933         /* if onlyents, just grab the entites and resave */
934         if( onlyents )
935         {
936                 OnlyEnts();
937                 return 0;
938         }
939         
940         /* load shaders */
941         LoadShaderInfo();
942         
943         /* load original file from temp spot in case it was renamed by the editor on the way in */
944         if( strlen( tempSource ) > 0 )
945                 LoadMapFile( tempSource, qfalse );
946         else
947                 LoadMapFile( name, qfalse );
948         
949         /* div0: inject command line parameters */
950         InjectCommandLine(argv, 1, argc - 1);
951         
952         /* ydnar: decal setup */
953         ProcessDecals();
954         
955         /* ydnar: cloned brush model entities */
956         SetCloneModelNumbers();
957         
958         /* process world and submodels */
959         ProcessModels();
960         
961         /* set light styles from targetted light entities */
962         SetLightStyles();
963         
964         /* process in game advertisements */
965         ProcessAdvertisements();
966
967         /* finish and write bsp */
968         EndBSPFile();
969         
970         /* remove temp map source file if appropriate */
971         if( strlen( tempSource ) > 0)
972                 remove( tempSource );
973         
974         /* return to sender */
975         return 0;
976 }
977