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