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