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