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