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