4f4c717269b136811d26493385614a36d13b6252
[xonotic/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                                 if(colorsRGB)
461                                 {
462                                         color[0] = Image_LinearFloatFromsRGBFloat(color[0]);
463                                         color[1] = Image_LinearFloatFromsRGBFloat(color[1]);
464                                         color[2] = Image_LinearFloatFromsRGBFloat(color[2]);
465                                 }
466                                 
467                                 /* create the flare surface (note shader defaults automatically) */
468                                 DrawSurfaceForFlare( mapEntityNum, origin, normal, color, flareShader, lightStyle );
469                         }
470                 }
471         }
472         
473         /* add references to the final drawsurfs in the apropriate clusters */
474         FilterDrawsurfsIntoTree( e, tree );
475         
476         /* match drawsurfaces back to original brushsides (sof2) */
477         FixBrushSides( e );
478         
479         /* finish */
480         EndModel( e, tree->headnode );
481         FreeTree( tree );
482 }
483
484
485
486 /*
487 ProcessSubModel()
488 creates bsp + surfaces for other brush models
489 */
490
491 void ProcessSubModel( void )
492 {
493         entity_t        *e;
494         tree_t          *tree;
495         brush_t         *b, *bc;
496         node_t          *node;
497         
498         
499         /* start a brush model */
500         BeginModel();
501         e = &entities[ mapEntityNum ];
502         e->firstDrawSurf = numMapDrawSurfs;
503         
504         /* ydnar: gs mods */
505         ClearMetaTriangles();
506         
507         /* check for patches with adjacent edges that need to lod together */
508         PatchMapDrawSurfs( e );
509         
510         /* allocate a tree */
511         node = AllocNode();
512         node->planenum = PLANENUM_LEAF;
513         tree = AllocTree();
514         tree->headnode = node;
515         
516         /* add the sides to the tree */
517         ClipSidesIntoTree( e, tree );
518         
519         /* ydnar: create drawsurfs for triangle models */
520         AddTriangleModels( e );
521         
522         /* create drawsurfs for surface models */
523         AddEntitySurfaceModels( e );
524         
525         /* generate bsp brushes from map brushes */
526         EmitBrushes( e->brushes, &e->firstBrush, &e->numBrushes );
527
528         /* just put all the brushes in headnode */
529         for( b = e->brushes; b; b = b->next )
530         {
531                 bc = CopyBrush( b );
532                 bc->next = node->brushlist;
533                 node->brushlist = bc;
534         }
535         
536         /* subdivide each drawsurf as required by shader tesselation */
537         if( !nosubdivide )
538                 SubdivideFaceSurfaces( e, tree );
539         
540         /* add in any vertexes required to fix t-junctions */
541         if( !notjunc )
542                 FixTJunctions( e );
543         
544         /* ydnar: classify the surfaces and project lightmaps */
545         ClassifyEntitySurfaces( e );
546         
547         /* ydnar: project decals */
548         MakeEntityDecals( e );
549         
550         /* ydnar: meta surfaces */
551         MakeEntityMetaTriangles( e );
552         SmoothMetaTriangles();
553         FixMetaTJunctions();
554         MergeMetaTriangles();
555         
556         /* add references to the final drawsurfs in the apropriate clusters */
557         FilterDrawsurfsIntoTree( e, tree );
558         
559         /* match drawsurfaces back to original brushsides (sof2) */
560         FixBrushSides( e );
561         
562         /* finish */
563         EndModel( e, node );
564         FreeTree( tree );
565 }
566
567
568
569 /*
570 ProcessModels()
571 process world + other models into the bsp
572 */
573
574 void ProcessModels( void )
575 {
576         qboolean        oldVerbose;
577         entity_t        *entity;
578         
579         
580         /* preserve -v setting */
581         oldVerbose = verbose;
582         
583         /* start a new bsp */
584         BeginBSPFile();
585         
586         /* create map fogs */
587         CreateMapFogs();
588         
589         /* walk entity list */
590         for( mapEntityNum = 0; mapEntityNum < numEntities; mapEntityNum++ )
591         {
592                 /* get entity */
593                 entity = &entities[ mapEntityNum ];
594                 if( entity->brushes == NULL && entity->patches == NULL )
595                         continue;
596                 
597                 /* process the model */
598                 Sys_FPrintf( SYS_VRB, "############### model %i ###############\n", numBSPModels );
599                 if( mapEntityNum == 0 )
600                         ProcessWorldModel();
601                 else
602                         ProcessSubModel();
603                 
604                 /* potentially turn off the deluge of text */
605                 verbose = verboseEntities;
606         }
607         
608         /* restore -v setting */
609         verbose = oldVerbose;
610         
611         /* write fogs */
612         EmitFogs();
613
614         /* vortex: emit meta stats */
615         EmitMetaStats();
616 }
617
618
619
620 /*
621 OnlyEnts()
622 this is probably broken unless teamed with a radiant version that preserves entity order
623 */
624
625 void OnlyEnts( void )
626 {
627         char out[ 1024 ];
628
629         char save_cmdline[1024], save_version[1024], save_gridsize[1024];
630         const char *p;
631         
632         /* note it */
633         Sys_Printf( "--- OnlyEnts ---\n" );
634         
635         sprintf( out, "%s.bsp", source );
636         LoadBSPFile( out );
637
638         ParseEntities();
639         p = ValueForKey(&entities[0], "_q3map2_cmdline");
640         strncpy(save_cmdline, p, sizeof(save_cmdline));
641         save_cmdline[sizeof(save_cmdline)-1] = 0;
642         p = ValueForKey(&entities[0], "_q3map2_version");
643         strncpy(save_version, p, sizeof(save_version));
644         save_version[sizeof(save_version)-1] = 0;
645         p = ValueForKey(&entities[0], "gridsize");
646         strncpy(save_gridsize, p, sizeof(save_gridsize));
647         save_gridsize[sizeof(save_gridsize)-1] = 0;
648
649         numEntities = 0;
650
651         LoadShaderInfo();
652         LoadMapFile( name, qfalse, qfalse );
653         SetModelNumbers();
654         SetLightStyles();
655
656         if(*save_cmdline)
657                 SetKeyValue(&entities[0], "_q3map2_cmdline", save_cmdline);
658         if(*save_version)
659                 SetKeyValue(&entities[0], "_q3map2_version", save_version);
660         if(*save_gridsize)
661                 SetKeyValue(&entities[0], "gridsize", save_gridsize);
662         
663         numBSPEntities = numEntities;
664         UnparseEntities();
665         
666         WriteBSPFile( out );
667 }
668
669
670
671 /*
672 BSPMain() - ydnar
673 handles creation of a bsp from a map file
674 */
675
676 int BSPMain( int argc, char **argv )
677 {
678         int                     i;
679         char            path[ 1024 ], tempSource[ 1024 ];
680         qboolean        onlyents = qfalse;
681         
682         
683         /* note it */
684         Sys_Printf( "--- BSP ---\n" );
685         
686         SetDrawSurfacesBuffer();
687         mapDrawSurfs = safe_malloc( sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS );
688         memset( mapDrawSurfs, 0, sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS );
689         numMapDrawSurfs = 0;
690         
691         tempSource[ 0 ] = '\0';
692         globalCelShader[0] = 0;
693         
694         /* set standard game flags */
695         maxSurfaceVerts = game->maxSurfaceVerts;
696         maxSurfaceIndexes = game->maxSurfaceIndexes;
697         emitFlares = game->emitFlares;
698         texturesRGB = game->texturesRGB;
699         colorsRGB = game->colorsRGB;
700         
701         /* process arguments */
702         for( i = 1; i < (argc - 1); i++ )
703         {
704                 if( !strcmp( argv[ i ], "-onlyents" ) )
705                 {
706                         Sys_Printf( "Running entity-only compile\n" );
707                         onlyents = qtrue;
708                 }
709                 else if( !strcmp( argv[ i ], "-tempname" ) )
710                         strcpy( tempSource, argv[ ++i ] );
711                 else if( !strcmp( argv[ i ], "-tmpout" ) )
712                         strcpy( outbase, "/tmp" );
713                 else if( !strcmp( argv[ i ],  "-nowater" ) )
714                 {
715                         Sys_Printf( "Disabling water\n" );
716                         nowater = qtrue;
717                 }
718                 else if( !strcmp( argv[ i ], "-keeplights" ))
719                 {
720                         keepLights = qtrue;
721                         Sys_Printf( "Leaving light entities on map after compile\n" );
722                 }
723                 else if( !strcmp( argv[ i ],  "-nodetail" ) )
724                 {
725                         Sys_Printf( "Ignoring detail brushes\n") ;
726                         nodetail = qtrue;
727                 }
728                 else if( !strcmp( argv[ i ],  "-fulldetail" ) )
729                 {
730                         Sys_Printf( "Turning detail brushes into structural brushes\n" );
731                         fulldetail = qtrue;
732                 }
733                 else if( !strcmp( argv[ i ],  "-nofog" ) )
734                 {
735                         Sys_Printf( "Fog volumes disabled\n" );
736                         nofog = qtrue;
737                 }
738                 else if( !strcmp( argv[ i ],  "-nosubdivide" ) )
739                 {
740                         Sys_Printf( "Disabling brush face subdivision\n" );
741                         nosubdivide = qtrue;
742                 }
743                 else if( !strcmp( argv[ i ],  "-leaktest" ) )
744                 {
745                         Sys_Printf( "Leaktest enabled\n" );
746                         leaktest = qtrue;
747                 }
748                 else if( !strcmp( argv[ i ],  "-verboseentities" ) )
749                 {
750                         Sys_Printf( "Verbose entities enabled\n" );
751                         verboseEntities = qtrue;
752                 }
753                 else if( !strcmp( argv[ i ], "-nocurves" ) )
754                 {
755                         Sys_Printf( "Ignoring curved surfaces (patches)\n" );
756                         noCurveBrushes = qtrue;
757                 }
758                 else if( !strcmp( argv[ i ], "-notjunc" ) )
759                 {
760                         Sys_Printf( "T-junction fixing disabled\n" );
761                         notjunc = qtrue;
762                 }
763                 else if( !strcmp( argv[ i ], "-fakemap" ) )
764                 {
765                         Sys_Printf( "Generating fakemap.map\n" );
766                         fakemap = qtrue;
767                 }
768                 else if( !strcmp( argv[ i ],  "-samplesize" ) )
769                 {
770                         sampleSize = atoi( argv[ i + 1 ] );
771                         if( sampleSize < 1 )
772                                 sampleSize = 1;
773                         i++;
774                         Sys_Printf( "Lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
775                 }
776                 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
777                 {
778                         minSampleSize = atoi( argv[ i + 1 ] );
779                         if( minSampleSize < 1 )
780                                 minSampleSize = 1;
781                         i++;
782                         Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
783                 }
784                 else if( !strcmp( argv[ i ],  "-custinfoparms") )
785                 {
786                         Sys_Printf( "Custom info parms enabled\n" );
787                         useCustomInfoParms = qtrue;
788                 }
789                 
790                 /* sof2 args */
791                 else if( !strcmp( argv[ i ], "-rename" ) )
792                 {
793                         Sys_Printf( "Appending _bsp suffix to misc_model shaders (SOF2)\n" );
794                         renameModelShaders = qtrue;
795                 }
796                 
797                 /* ydnar args */
798                 else if( !strcmp( argv[ i ],  "-ne" ) )
799                 {
800                         normalEpsilon = atof( argv[ i + 1 ] );
801                         i++;
802                         Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
803                 }
804                 else if( !strcmp( argv[ i ],  "-de" ) )
805                 {
806                         distanceEpsilon = atof( argv[ i + 1 ] );
807                         i++;
808                         Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
809                 }
810                 else if( !strcmp( argv[ i ],  "-mv" ) )
811                 {
812                         maxLMSurfaceVerts = atoi( argv[ i + 1 ] );
813                         if( maxLMSurfaceVerts < 3 )
814                                 maxLMSurfaceVerts = 3;
815                         if( maxLMSurfaceVerts > maxSurfaceVerts )
816                                 maxSurfaceVerts = maxLMSurfaceVerts;
817                         i++;
818                         Sys_Printf( "Maximum lightmapped surface vertex count set to %d\n", maxLMSurfaceVerts );
819                 }
820                 else if( !strcmp( argv[ i ],  "-mi" ) )
821                 {
822                         maxSurfaceIndexes = atoi( argv[ i + 1 ] );
823                         if( maxSurfaceIndexes < 3 )
824                                 maxSurfaceIndexes = 3;
825                         i++;
826                         Sys_Printf( "Maximum per-surface index count set to %d\n", maxSurfaceIndexes );
827                 }
828                 else if( !strcmp( argv[ i ], "-np" ) )
829                 {
830                         npDegrees = atof( argv[ i + 1 ] );
831                         if( npDegrees < 0.0f )
832                                 npDegrees = 0.0f;
833                         else if( npDegrees > 0.0f )
834                                 Sys_Printf( "Forcing nonplanar surfaces with a breaking angle of %f degrees\n", npDegrees );
835                         i++;
836                 }
837                 else if( !strcmp( argv[ i ],  "-snap" ) )
838                 {
839                         bevelSnap = atoi( argv[ i + 1 ]);
840                         if( bevelSnap < 0 )
841                                 bevelSnap = 0;
842                         i++;
843                         if( bevelSnap > 0 )
844                                 Sys_Printf( "Snapping brush bevel planes to %d units\n", bevelSnap );
845                 }
846                 else if( !strcmp( argv[ i ],  "-texrange" ) )
847                 {
848                         texRange = atoi( argv[ i + 1 ]);
849                         if( texRange < 0 )
850                                 texRange = 0;
851                         i++;
852                         Sys_Printf( "Limiting per-surface texture range to %d texels\n", texRange );
853                 }
854                 else if( !strcmp( argv[ i ], "-nohint" ) )
855                 {
856                         Sys_Printf( "Hint brushes disabled\n" );
857                         noHint = qtrue;
858                 }
859                 else if( !strcmp( argv[ i ], "-flat" ) )
860                 {
861                         Sys_Printf( "Flatshading enabled\n" );
862                         flat = qtrue;
863                 }
864                 else if( !strcmp( argv[ i ], "-celshader" ) )
865                 {
866                         ++i;
867                         if(argv[i][0])
868                                 sprintf( globalCelShader, "textures/%s", argv[ i ] );
869                         else
870                                 *globalCelShader = 0;
871                         Sys_Printf( "Global cel shader set to \"%s\"\n", globalCelShader );
872                 }
873                 else if( !strcmp( argv[ i ], "-meta" ) )
874                 {
875                         Sys_Printf( "Creating meta surfaces from brush faces\n" );
876                         meta = qtrue;
877                 }
878                 else if( !strcmp( argv[ i ], "-metaadequatescore" ) )
879                 {
880                         metaAdequateScore = atoi( argv[ i + 1 ]);
881                         if( metaAdequateScore < 0 )
882                                 metaAdequateScore = -1;
883                         i++;
884                         if( metaAdequateScore >= 0 )
885                                 Sys_Printf( "Setting ADEQUATE meta score to %d (see surface_meta.c)\n", metaAdequateScore );
886                 }
887                 else if( !strcmp( argv[ i ], "-metagoodscore" ) )
888                 {
889                         metaGoodScore = atoi( argv[ i + 1 ]);
890                         if( metaGoodScore < 0 )
891                                 metaGoodScore = -1;
892                         i++;
893                         if( metaGoodScore >= 0 )
894                                 Sys_Printf( "Setting GOOD meta score to %d (see surface_meta.c)\n", metaGoodScore );
895                 }
896                 else if( !strcmp( argv[ i ], "-metamaxbboxdistance" ) )
897                 {
898                         metaMaxBBoxDistance = atof( argv[ i + 1 ]);
899                         if( metaMaxBBoxDistance < 0 )
900                                 metaMaxBBoxDistance = -1;
901                         i++;
902                         if( metaMaxBBoxDistance >= 0 )
903                                 Sys_Printf( "Setting meta maximum bounding box distance to %f\n", metaMaxBBoxDistance );
904                 }
905                 else if( !strcmp( argv[ i ], "-patchmeta" ) )
906                 {
907                         Sys_Printf( "Creating meta surfaces from patches\n" );
908                         patchMeta = qtrue;
909                 }
910                 else if( !strcmp( argv[ i ], "-flares" ) )
911                 {
912                         Sys_Printf( "Flare surfaces enabled\n" );
913                         emitFlares = qtrue;
914                 }
915                 else if( !strcmp( argv[ i ], "-noflares" ) )
916                 {
917                         Sys_Printf( "Flare surfaces disabled\n" );
918                         emitFlares = qfalse;
919                 }
920                 else if( !strcmp( argv[ i ], "-skyfix" ) )
921                 {
922                         Sys_Printf( "GL_CLAMP sky fix/hack/workaround enabled\n" );
923                         skyFixHack = qtrue;
924                 }
925                 else if( !strcmp( argv[ i ], "-debugsurfaces" ) )
926                 {
927                         Sys_Printf( "emitting debug surfaces\n" );
928                         debugSurfaces = qtrue;
929                 }
930                 else if( !strcmp( argv[ i ], "-debuginset" ) )
931                 {
932                         Sys_Printf( "Debug surface triangle insetting enabled\n" );
933                         debugInset = qtrue;
934                 }
935                 else if( !strcmp( argv[ i ], "-debugportals" ) )
936                 {
937                         Sys_Printf( "Debug portal surfaces enabled\n" );
938                         debugPortals = qtrue;
939                 }
940                 else if( !strcmp( argv[ i ], "-sRGBtex" ) )
941                 {
942                         texturesRGB = qtrue;
943                         Sys_Printf( "Textures are in sRGB\n" );
944                 }
945                 else if( !strcmp( argv[ i ], "-nosRGBtex" ) )
946                 {
947                         texturesRGB = qfalse;
948                         Sys_Printf( "Textures are linear\n" );
949                 }
950                 else if( !strcmp( argv[ i ], "-sRGBcolor" ) )
951                 {
952                         colorsRGB = qtrue;
953                         Sys_Printf( "Colors are in sRGB\n" );
954                 }
955                 else if( !strcmp( argv[ i ], "-nosRGBcolor" ) )
956                 {
957                         colorsRGB = qfalse;
958                         Sys_Printf( "Colors are linear\n" );
959                 }
960                 else if( !strcmp( argv[ i ], "-nosRGB" ) )
961                 {
962                         texturesRGB = qfalse;
963                         Sys_Printf( "Textures are linear\n" );
964                         colorsRGB = qfalse;
965                         Sys_Printf( "Colors are linear\n" );
966                 }
967                 else if( !strcmp( argv[ i ], "-altsplit" ) )
968                 {
969                         Sys_Printf( "Alternate BSP splitting (by 27) enabled\n" );
970                         bspAlternateSplitWeights = qtrue;
971                 }
972                 else if( !strcmp( argv[ i ], "-deep" ) )
973                 {
974                         Sys_Printf( "Deep BSP tree generation enabled\n" );
975                         deepBSP = qtrue;
976                 }
977                 else if( !strcmp( argv[ i ], "-maxarea" ) )
978                 {
979                         Sys_Printf( "Max Area face surface generation enabled\n" );
980                         maxAreaFaceSurface = qtrue;
981                 }
982                 else if( !strcmp( argv[ i ], "-bsp" ) )
983                         Sys_Printf( "-bsp argument unnecessary\n" );
984                 else
985                 {
986                         Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );
987                 }
988         }
989         
990         /* fixme: print more useful usage here */
991         if( i != (argc - 1) )
992                 Error( "usage: q3map [options] mapfile" );
993         
994         /* copy source name */
995         strcpy( source, ExpandArg( argv[ i ] ) );
996         StripExtension( source );
997         
998         /* ydnar: set default sample size */
999         SetDefaultSampleSize( sampleSize );
1000         
1001         /* delete portal, line and surface files */
1002         sprintf( path, "%s.prt", source );
1003         remove( path );
1004         sprintf( path, "%s.lin", source );
1005         remove( path );
1006         //%     sprintf( path, "%s.srf", source );      /* ydnar */
1007         //%     remove( path );
1008         
1009         /* expand mapname */
1010         strcpy( name, ExpandArg( argv[ i ] ) ); 
1011         if( strcmp( name + strlen( name ) - 4, ".reg" ) )
1012         {
1013                 /* if we are doing a full map, delete the last saved region map */
1014                 sprintf( path, "%s.reg", source );
1015                 remove( path );
1016                 DefaultExtension( name, ".map" );       /* might be .reg */
1017         }
1018         
1019         /* if onlyents, just grab the entites and resave */
1020         if( onlyents )
1021         {
1022                 OnlyEnts();
1023                 return 0;
1024         }
1025         
1026         /* load shaders */
1027         LoadShaderInfo();
1028         
1029         /* load original file from temp spot in case it was renamed by the editor on the way in */
1030         if( strlen( tempSource ) > 0 )
1031                 LoadMapFile( tempSource, qfalse, qfalse );
1032         else
1033                 LoadMapFile( name, qfalse, qfalse );
1034         
1035         /* div0: inject command line parameters */
1036         InjectCommandLine(argv, 1, argc - 1);
1037         
1038         /* ydnar: decal setup */
1039         ProcessDecals();
1040         
1041         /* ydnar: cloned brush model entities */
1042         SetCloneModelNumbers();
1043         
1044         /* process world and submodels */
1045         ProcessModels();
1046         
1047         /* set light styles from targetted light entities */
1048         SetLightStyles();
1049         
1050         /* process in game advertisements */
1051         ProcessAdvertisements();
1052
1053         /* finish and write bsp */
1054         EndBSPFile(qtrue);
1055         
1056         /* remove temp map source file if appropriate */
1057         if( strlen( tempSource ) > 0)
1058                 remove( tempSource );
1059         
1060         /* return to sender */
1061         return 0;
1062 }
1063