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