]> icculus.org git repositories - divverent/netradiant.git/blob - tools/quake3/q3map2/map.c
command line options for minimap
[divverent/netradiant.git] / tools / quake3 / q3map2 / map.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 MAP_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41 /* FIXME: remove these vars */
42
43 /* undefine to make plane finding use linear sort (note: really slow) */
44 #define USE_HASHING
45 #define PLANE_HASHES    8192
46
47 int                                             planehash[ PLANE_HASHES ];
48
49 int                                             c_boxbevels;
50 int                                             c_edgebevels;
51 int                                             c_areaportals;
52 int                                             c_detail;
53 int                                             c_structural;
54
55
56
57 /*
58 PlaneEqual()
59 ydnar: replaced with variable epsilon for djbob
60 */
61
62 #define NORMAL_EPSILON  0.00001
63 #define DIST_EPSILON    0.01
64
65 qboolean PlaneEqual( plane_t *p, vec3_t normal, vec_t dist )
66 {
67         float   ne, de;
68         
69         
70         /* get local copies */
71         ne = normalEpsilon;
72         de = distanceEpsilon;
73         
74         /* compare */
75         if( fabs( p->dist - dist ) <= de &&
76                 fabs( p->normal[ 0 ] - normal[ 0 ] ) <= ne &&
77                 fabs( p->normal[ 1 ] - normal[ 1 ] ) <= ne &&
78                 fabs( p->normal[ 2 ] - normal[ 2 ] ) <= ne )
79                 return qtrue;
80         
81         /* different */
82         return qfalse;
83 }
84
85
86
87 /*
88 AddPlaneToHash()
89 */
90
91 void AddPlaneToHash( plane_t *p )
92 {
93         int             hash;
94
95         
96         hash = (PLANE_HASHES - 1) & (int) fabs( p->dist );
97
98         p->hash_chain = planehash[hash];
99         planehash[hash] = p - mapplanes + 1;
100 }
101
102 /*
103 ================
104 CreateNewFloatPlane
105 ================
106 */
107 int CreateNewFloatPlane (vec3_t normal, vec_t dist)
108 {
109         plane_t *p, temp;
110
111         if (VectorLength(normal) < 0.5)
112         {
113                 Sys_Printf( "FloatPlane: bad normal\n");
114                 return -1;
115         }
116
117         // create a new plane
118         AUTOEXPAND_BY_REALLOC(mapplanes, nummapplanes+1, allocatedmapplanes, 1024);
119
120         p = &mapplanes[nummapplanes];
121         VectorCopy (normal, p->normal);
122         p->dist = dist;
123         p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
124
125         VectorSubtract (vec3_origin, normal, (p+1)->normal);
126         (p+1)->dist = -dist;
127
128         nummapplanes += 2;
129
130         // allways put axial planes facing positive first
131         if (p->type < 3)
132         {
133                 if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
134                 {
135                         // flip order
136                         temp = *p;
137                         *p = *(p+1);
138                         *(p+1) = temp;
139
140                         AddPlaneToHash (p);
141                         AddPlaneToHash (p+1);
142                         return nummapplanes - 1;
143                 }
144         }
145
146         AddPlaneToHash (p);
147         AddPlaneToHash (p+1);
148         return nummapplanes - 2;
149 }
150
151
152
153 /*
154 SnapNormal()
155 snaps a near-axial normal vector
156 */
157
158 void SnapNormal( vec3_t normal )
159 {
160         int             i;
161
162         for( i = 0; i < 3; i++ )
163         {
164                 if( fabs( normal[ i ] - 1 ) < normalEpsilon )
165                 {
166                         VectorClear( normal );
167                         normal[ i ] = 1;
168                         break;
169                 }
170                 if( fabs( normal[ i ] - -1 ) < normalEpsilon )
171                 {
172                         VectorClear( normal );
173                         normal[ i ] = -1;
174                         break;
175                 }
176         }
177 }
178
179
180
181 /*
182 SnapPlane()
183 snaps a plane to normal/distance epsilons
184 */
185
186 void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
187 {
188 // SnapPlane disabled by LordHavoc because it often messes up collision
189 // brushes made from triangles of embedded models, and it has little effect
190 // on anything else (axial planes are usually derived from snapped points)
191 /*
192   SnapPlane reenabled by namespace because of multiple reports of
193   q3map2-crashes which were triggered by this patch.
194 */
195         // div0: ensure the point "center" stays on the plane (actually, this
196         // rotates the plane around the point center).
197         // if center lies on the plane, it is guaranteed to stay on the plane by
198         // this fix.
199         vec_t centerDist = DotProduct(normal, center);
200         SnapNormal( normal );
201         *dist += (DotProduct(normal, center) - centerDist);
202
203         if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
204                 *dist = Q_rint( *dist );
205 }
206
207
208
209 /*
210 FindFloatPlane()
211 ydnar: changed to allow a number of test points to be supplied that
212 must be within an epsilon distance of the plane
213 */
214
215 int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ) // NOTE: this has a side effect on the normal. Good or bad?
216
217 #ifdef USE_HASHING
218
219 {
220         int             i, j, hash, h;
221         int pidx;
222         plane_t *p;
223         vec_t   d;
224         vec3_t centerofweight;
225
226         VectorClear(centerofweight);
227         for(i = 0; i < numPoints; ++i)
228                 VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
229         
230         /* hash the plane */
231         SnapPlane( normal, &dist, centerofweight );
232         hash = (PLANE_HASHES - 1) & (int) fabs( dist );
233         
234         /* search the border bins as well */
235         for( i = -1; i <= 1; i++ )
236         {
237                 h = (hash + i) & (PLANE_HASHES - 1);
238                 for( pidx = planehash[ h ] - 1; pidx != -1; pidx = mapplanes[pidx].hash_chain - 1 )
239                 {
240                         p = &mapplanes[pidx];
241
242                         /* do standard plane compare */
243                         if( !PlaneEqual( p, normal, dist ) )
244                                 continue;
245                         
246                         /* ydnar: uncomment the following line for old-style plane finding */
247                         //%     return p - mapplanes;
248                         
249                         /* ydnar: test supplied points against this plane */
250                         for( j = 0; j < numPoints; j++ )
251                         {
252                                 d = DotProduct( points[ j ], normal ) - dist;
253                                 if( fabs( d ) > distanceEpsilon )
254                                         break;
255                         }
256                         
257                         /* found a matching plane */
258                         if( j >= numPoints )
259                                 return p - mapplanes;
260                 }
261         }
262         
263         /* none found, so create a new one */
264         return CreateNewFloatPlane( normal, dist );
265 }
266
267 #else
268
269 {
270         int             i;
271         plane_t *p;
272         
273
274         vec3_t centerofweight;
275
276         VectorClear(centerofweight);
277         for(i = 0; i < numPoints; ++i)
278                 VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
279
280         SnapPlane( normal, &dist, centerofweight );
281         for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
282         {
283                 if( PlaneEqual( p, normal, dist ) )
284                         return i;
285         }
286         
287         return CreateNewFloatPlane( normal, dist );
288 }
289
290 #endif
291
292
293
294 /*
295 MapPlaneFromPoints()
296 takes 3 points and finds the plane they lie in
297 */
298
299 int MapPlaneFromPoints( vec3_t *p )
300 {
301         vec3_t  t1, t2, normal;
302         vec_t   dist;
303         
304         
305         /* calc plane normal */
306         VectorSubtract( p[ 0 ], p[ 1 ], t1 );
307         VectorSubtract( p[ 2 ], p[ 1 ], t2 );
308         CrossProduct( t1, t2, normal );
309         VectorNormalize( normal, normal );
310         
311         /* calc plane distance */
312         dist = DotProduct( p[ 0 ], normal );
313         
314         /* store the plane */
315         return FindFloatPlane( normal, dist, 3, p );
316 }
317
318
319
320 /*
321 SetBrushContents()
322 the content flags and compile flags on all sides of a brush should be the same
323 */
324
325 void SetBrushContents( brush_t *b )
326 {
327         int                     contentFlags, compileFlags;
328         side_t          *s;
329         int                     i;
330         qboolean        mixed;
331         
332         
333         /* get initial compile flags from first side */
334         s = &b->sides[ 0 ];
335         contentFlags = s->contentFlags;
336         compileFlags = s->compileFlags;
337         b->contentShader = s->shaderInfo;
338         mixed = qfalse;
339         
340         /* get the content/compile flags for every side in the brush */
341         for( i = 1; i < b->numsides; i++, s++ )
342         {
343                 s = &b->sides[ i ];
344                 if( s->shaderInfo == NULL )
345                         continue;
346                 if( s->contentFlags != contentFlags || s->compileFlags != compileFlags )
347                         mixed = qtrue;
348         }
349         
350         /* ydnar: getting rid of this stupid warning */
351         //%     if( mixed )
352         //%             Sys_FPrintf( SYS_VRB,"Entity %i, Brush %i: mixed face contentFlags\n", b->entitynum, b->brushnum );
353
354         /* check for detail & structural */
355         if( (compileFlags & C_DETAIL) && (compileFlags & C_STRUCTURAL) )
356         {
357                 xml_Select( "Mixed detail and structural (defaulting to structural)", mapEnt->mapEntityNum, entitySourceBrushes, qfalse );
358                 compileFlags &= ~C_DETAIL;
359         }
360         
361         /* the fulldetail flag will cause detail brushes to be treated like normal brushes */
362         if( fulldetail )
363                 compileFlags &= ~C_DETAIL;
364         
365         /* all translucent brushes that aren't specifically made structural will be detail */
366         if( (compileFlags & C_TRANSLUCENT) && !(compileFlags & C_STRUCTURAL) )
367                 compileFlags |= C_DETAIL;
368         
369         /* detail? */
370         if( compileFlags & C_DETAIL )
371         {
372                 c_detail++;
373                 b->detail = qtrue;
374         }
375         else
376         {
377                 c_structural++;
378                 b->detail = qfalse;
379         }
380         
381         /* opaque? */
382         if( compileFlags & C_TRANSLUCENT )
383                 b->opaque = qfalse;
384         else
385                 b->opaque = qtrue;
386         
387         /* areaportal? */
388         if( compileFlags & C_AREAPORTAL )
389                 c_areaportals++;
390         
391         /* set brush flags */
392         b->contentFlags = contentFlags;
393         b->compileFlags = compileFlags;
394 }
395
396
397
398 /*
399 AddBrushBevels()
400 adds any additional planes necessary to allow the brush being
401 built to be expanded against axial bounding boxes
402 ydnar 2003-01-20: added mrelusive fixes
403 */
404
405 void AddBrushBevels( void )
406 {
407         int                     axis, dir;
408         int                     i, j, k, l, order;
409         side_t          sidetemp;
410         side_t          *s, *s2;
411         winding_t       *w, *w2;
412         vec3_t          normal;
413         float           dist;
414         vec3_t          vec, vec2;
415         float           d, minBack;
416
417         //
418         // add the axial planes
419         //
420         order = 0;
421         for ( axis = 0; axis < 3; axis++ ) {
422                 for ( dir = -1; dir <= 1; dir += 2, order++ ) {
423                         // see if the plane is allready present
424                         for ( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ )
425                         {
426                                 /* ydnar: testing disabling of mre code */
427                                 #if 0
428                                         if ( dir > 0 ) {
429                                                 if ( mapplanes[s->planenum].normal[axis] >= 0.9999f ) {
430                                                         break;
431                                                 }
432                                         }
433                                         else {
434                                                 if ( mapplanes[s->planenum].normal[axis] <= -0.9999f ) {
435                                                         break;
436                                                 }
437                                         }
438                                 #else
439                                         if( (dir > 0 && mapplanes[ s->planenum ].normal[ axis ] == 1.0f ) ||
440                                                 (dir < 0 && mapplanes[ s->planenum ].normal[ axis ] == -1.0f) )
441                                                 break;
442                                 #endif
443                         }
444
445                         if ( i == buildBrush->numsides ) {
446                                 // add a new side
447                                 if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
448                                         xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
449                                 }
450                                 memset( s, 0, sizeof( *s ) );
451                                 buildBrush->numsides++;
452                                 VectorClear (normal);
453                                 normal[axis] = dir;
454
455                                 if( dir == 1 )
456                                 {
457                                         /* ydnar: adding bevel plane snapping for fewer bsp planes */
458                                         if( bevelSnap > 0 )
459                                                 dist = floor( buildBrush->maxs[ axis ] / bevelSnap ) * bevelSnap;
460                                         else
461                                                 dist = buildBrush->maxs[ axis ];
462                                 }
463                                 else
464                                 {
465                                         /* ydnar: adding bevel plane snapping for fewer bsp planes */
466                                         if( bevelSnap > 0 )
467                                                 dist = -ceil( buildBrush->mins[ axis ] / bevelSnap ) * bevelSnap;
468                                         else
469                                                 dist = -buildBrush->mins[ axis ];
470                                 }
471
472                                 s->planenum = FindFloatPlane( normal, dist, 0, NULL );
473                                 s->contentFlags = buildBrush->sides[ 0 ].contentFlags;
474                                 s->bevel = qtrue;
475                                 c_boxbevels++;
476                         }
477
478                         // if the plane is not in it canonical order, swap it
479                         if ( i != order ) {
480                                 sidetemp = buildBrush->sides[order];
481                                 buildBrush->sides[order] = buildBrush->sides[i];
482                                 buildBrush->sides[i] = sidetemp;
483                         }
484                 }
485         }
486
487         //
488         // add the edge bevels
489         //
490         if ( buildBrush->numsides == 6 ) {
491                 return;         // pure axial
492         }
493
494         // test the non-axial plane edges
495         for ( i = 6; i < buildBrush->numsides; i++ ) {
496                 s = buildBrush->sides + i;
497                 w = s->winding;
498                 if ( !w ) {
499                         continue;
500                 }
501                 for ( j = 0; j < w->numpoints; j++) {
502                         k = (j+1)%w->numpoints;
503                         VectorSubtract( w->p[j], w->p[k], vec );
504                         if ( VectorNormalize( vec, vec ) < 0.5f ) {
505                                 continue;
506                         }
507                         SnapNormal( vec );
508                         for ( k = 0; k < 3; k++ ) {
509                                 if ( vec[k] == -1.0f || vec[k] == 1.0f || (vec[k] == 0.0f && vec[(k+1)%3] == 0.0f) ) {
510                                         break;  // axial
511                                 }
512                         }
513                         if ( k != 3 ) {
514                                 continue;       // only test non-axial edges
515                         }
516
517                         /* debug code */
518                         //%     Sys_Printf( "-------------\n" );
519
520                         // try the six possible slanted axials from this edge
521                         for ( axis = 0; axis < 3; axis++ ) {
522                                 for ( dir = -1; dir <= 1; dir += 2 ) {
523                                         // construct a plane
524                                         VectorClear( vec2 );
525                                         vec2[axis] = dir;
526                                         CrossProduct( vec, vec2, normal );
527                                         if ( VectorNormalize( normal, normal ) < 0.5f ) {
528                                                 continue;
529                                         }
530                                         dist = DotProduct( w->p[j], normal );
531                                         
532                                         // if all the points on all the sides are
533                                         // behind this plane, it is a proper edge bevel
534                                         for ( k = 0; k < buildBrush->numsides; k++ ) {
535
536                                                 // if this plane has allready been used, skip it
537                                                 if ( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist ) ) {
538                                                         break;
539                                                 }
540
541                                                 w2 = buildBrush->sides[k].winding;
542                                                 if ( !w2 ) {
543                                                         continue;
544                                                 }
545                                                 minBack = 0.0f;
546                                                 for ( l = 0; l < w2->numpoints; l++ ) {
547                                                         d = DotProduct( w2->p[l], normal ) - dist;
548                                                         if ( d > 0.1f ) {
549                                                                 break;  // point in front
550                                                         }
551                                                         if ( d < minBack ) {
552                                                                 minBack = d;
553                                                         }
554                                                 }
555                                                 // if some point was at the front
556                                                 if ( l != w2->numpoints ) {
557                                                         break;
558                                                 }
559
560                                                 // if no points at the back then the winding is on the bevel plane
561                                                 if ( minBack > -0.1f ) {
562                                                         //%     Sys_Printf( "On bevel plane\n" );
563                                                         break;
564                                                 }
565                                         }
566
567                                         if ( k != buildBrush->numsides ) {
568                                                 continue;       // wasn't part of the outer hull
569                                         }
570                                         
571                                         /* debug code */
572                                         //%     Sys_Printf( "n = %f %f %f\n", normal[ 0 ], normal[ 1 ], normal[ 2 ] );
573                                         
574                                         // add this plane
575                                         if( buildBrush->numsides == MAX_BUILD_SIDES ) {
576                                                 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
577                                         }
578                                         s2 = &buildBrush->sides[buildBrush->numsides];
579                                         buildBrush->numsides++;
580                                         memset( s2, 0, sizeof( *s2 ) );
581
582                                         s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[ j ] );
583                                         s2->contentFlags = buildBrush->sides[0].contentFlags;
584                                         s2->bevel = qtrue;
585                                         c_edgebevels++;
586                                 }
587                         }
588                 }
589         }
590 }
591
592
593
594 /*
595 FinishBrush()
596 produces a final brush based on the buildBrush->sides array
597 and links it to the current entity
598 */
599
600 static void MergeOrigin(entity_t *ent, vec3_t origin)
601 {
602         vec3_t adjustment;
603         char string[128];
604
605         /* we have not parsed the brush completely yet... */
606         GetVectorForKey( ent, "origin", ent->origin );
607
608         VectorMA(origin, -1, ent->originbrush_origin, adjustment);
609         VectorAdd(adjustment, ent->origin, ent->origin);
610         VectorCopy(origin, ent->originbrush_origin);
611
612         sprintf(string, "%f %f %f", ent->origin[0], ent->origin[1], ent->origin[2]);
613         SetKeyValue(ent, "origin", string);
614 }
615
616 brush_t *FinishBrush( void )
617 {
618         brush_t         *b;
619         
620         
621         /* create windings for sides and bounds for brush */
622         if ( !CreateBrushWindings( buildBrush ) )
623                 return NULL;
624
625         /* origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity.
626            after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
627         if( buildBrush->compileFlags & C_ORIGIN )
628         {
629                 vec3_t  origin;
630
631                 Sys_Printf( "Entity %i, Brush %i: origin brush detected\n", 
632                                 mapEnt->mapEntityNum, entitySourceBrushes );
633
634                 if( numEntities == 1 )
635                 {
636                         Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n", 
637                                 mapEnt->mapEntityNum, entitySourceBrushes );
638                         return NULL;
639                 }
640                 
641                 VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
642                 VectorScale (origin, 0.5, origin);
643
644                 MergeOrigin(&entities[ numEntities - 1 ], origin);
645
646                 /* don't keep this brush */
647                 return NULL;
648         }
649         
650         /* determine if the brush is an area portal */
651         if( buildBrush->compileFlags & C_AREAPORTAL )
652         {
653                 if( numEntities != 1 )
654                 {
655                         Sys_Printf ("Entity %i, Brush %i: areaportals only allowed in world\n", numEntities - 1, entitySourceBrushes );
656                         return NULL;
657                 }
658         }
659         
660         /* add bevel planes */
661         AddBrushBevels();
662         
663         /* keep it */
664         b = CopyBrush( buildBrush );
665         
666         /* set map entity and brush numbering */
667         b->entityNum = mapEnt->mapEntityNum;
668         b->brushNum = entitySourceBrushes;
669         
670         /* set original */
671         b->original = b;
672         
673         /* link opaque brushes to head of list, translucent brushes to end */
674         if( b->opaque || mapEnt->lastBrush == NULL )
675         {
676                 b->next = mapEnt->brushes;
677                 mapEnt->brushes = b;
678                 if( mapEnt->lastBrush == NULL )
679                         mapEnt->lastBrush = b;
680         }
681         else
682         {
683                 b->next = NULL;
684                 mapEnt->lastBrush->next = b;
685                 mapEnt->lastBrush = b;
686         }
687         
688         /* link colorMod volume brushes to the entity directly */
689         if( b->contentShader != NULL &&
690                 b->contentShader->colorMod != NULL &&
691                 b->contentShader->colorMod->type == CM_VOLUME )
692         {
693                 b->nextColorModBrush = mapEnt->colorModBrushes;
694                 mapEnt->colorModBrushes = b;
695         }
696         
697         /* return to sender */
698         return b;
699 }
700
701
702
703 /*
704 TextureAxisFromPlane()
705 determines best orthagonal axis to project a texture onto a wall
706 (must be identical in radiant!)
707 */
708
709 vec3_t  baseaxis[18] =
710 {
711         {0,0,1}, {1,0,0}, {0,-1,0},                     // floor
712         {0,0,-1}, {1,0,0}, {0,-1,0},            // ceiling
713         {1,0,0}, {0,1,0}, {0,0,-1},                     // west wall
714         {-1,0,0}, {0,1,0}, {0,0,-1},            // east wall
715         {0,1,0}, {1,0,0}, {0,0,-1},                     // south wall
716         {0,-1,0}, {1,0,0}, {0,0,-1}                     // north wall
717 };
718
719 void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv )
720 {
721         int             bestaxis;
722         vec_t   dot,best;
723         int             i;
724         
725         best = 0;
726         bestaxis = 0;
727         
728         for (i=0 ; i<6 ; i++)
729         {
730                 dot = DotProduct (pln->normal, baseaxis[i*3]);
731                 if( dot > best + 0.0001f )      /* ydnar: bug 637 fix, suggested by jmonroe */
732                 {
733                         best = dot;
734                         bestaxis = i;
735                 }
736         }
737         
738         VectorCopy (baseaxis[bestaxis*3+1], xv);
739         VectorCopy (baseaxis[bestaxis*3+2], yv);
740 }
741
742
743
744 /*
745 QuakeTextureVecs()
746 creates world-to-texture mapping vecs for crappy quake plane arrangements
747 */
748
749 void QuakeTextureVecs( plane_t *plane, vec_t shift[ 2 ], vec_t rotate, vec_t scale[ 2 ], vec_t mappingVecs[ 2 ][ 4 ] )
750 {
751         vec3_t  vecs[2];
752         int             sv, tv;
753         vec_t   ang, sinv, cosv;
754         vec_t   ns, nt;
755         int             i, j;
756         
757         
758         TextureAxisFromPlane(plane, vecs[0], vecs[1]);
759         
760         if (!scale[0])
761                 scale[0] = 1;
762         if (!scale[1])
763                 scale[1] = 1;
764
765         // rotate axis
766         if (rotate == 0)
767                 { sinv = 0 ; cosv = 1; }
768         else if (rotate == 90)
769                 { sinv = 1 ; cosv = 0; }
770         else if (rotate == 180)
771                 { sinv = 0 ; cosv = -1; }
772         else if (rotate == 270)
773                 { sinv = -1 ; cosv = 0; }
774         else
775         {       
776                 ang = rotate / 180 * Q_PI;
777                 sinv = sin(ang);
778                 cosv = cos(ang);
779         }
780
781         if (vecs[0][0])
782                 sv = 0;
783         else if (vecs[0][1])
784                 sv = 1;
785         else
786                 sv = 2;
787                                 
788         if (vecs[1][0])
789                 tv = 0;
790         else if (vecs[1][1])
791                 tv = 1;
792         else
793                 tv = 2;
794                                         
795         for (i=0 ; i<2 ; i++) {
796                 ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
797                 nt = sinv * vecs[i][sv] +  cosv * vecs[i][tv];
798                 vecs[i][sv] = ns;
799                 vecs[i][tv] = nt;
800         }
801
802         for (i=0 ; i<2 ; i++)
803                 for (j=0 ; j<3 ; j++)
804                         mappingVecs[i][j] = vecs[i][j] / scale[i];
805
806         mappingVecs[0][3] = shift[0];
807         mappingVecs[1][3] = shift[1];
808 }
809
810
811
812 /*
813 ParseRawBrush()
814 parses the sides into buildBrush->sides[], nothing else.
815 no validation, back plane removal, etc.
816
817 Timo - 08/26/99
818 added brush epairs parsing ( ignoring actually )
819 Timo - 08/04/99
820 added exclusive brush primitive parsing
821 Timo - 08/08/99
822 support for old brush format back in
823 NOTE: it would be "cleaner" to have seperate functions to parse between old and new brushes
824 */
825
826 static void ParseRawBrush( qboolean onlyLights )
827 {
828         side_t                  *side;
829         vec3_t                  planePoints[ 3 ];
830         int                             planenum;
831         shaderInfo_t    *si;
832         vec_t                   shift[ 2 ];
833         vec_t                   rotate;
834         vec_t                   scale[ 2 ];
835         char                    name[ MAX_QPATH ];
836         char                    shader[ MAX_QPATH ];
837         int                             flags;
838         
839         
840         /* initial setup */
841         buildBrush->numsides = 0;
842         buildBrush->detail = qfalse;
843         
844         /* bp */
845         if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
846                 MatchToken( "{" );
847         
848         /* parse sides */
849         while( 1 )
850         {
851                 if( !GetToken( qtrue ) )
852                         break;
853                 if( !strcmp( token, "}" ) )
854                         break;
855                  
856                 /* ttimo : bp: here we may have to jump over brush epairs (only used in editor) */
857                 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
858                 {
859                         while( 1 )
860                         {
861                                 if( strcmp( token, "(" ) )
862                                         GetToken( qfalse );
863                                 else
864                                         break;
865                                 GetToken( qtrue );
866                         }
867                 }
868                 UnGetToken();
869                 
870                 /* test side count */
871                 if( buildBrush->numsides >= MAX_BUILD_SIDES )
872                         xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
873                 
874                 /* add side */
875                 side = &buildBrush->sides[ buildBrush->numsides ];
876                 memset( side, 0, sizeof( *side ) );
877                 buildBrush->numsides++;
878                 
879                 /* read the three point plane definition */
880                 Parse1DMatrix( 3, planePoints[ 0 ] );
881                 Parse1DMatrix( 3, planePoints[ 1 ] );
882                 Parse1DMatrix( 3, planePoints[ 2 ] );
883                 
884                 /* bp: read the texture matrix */
885                 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
886                         Parse2DMatrix( 2, 3, (float*) side->texMat );
887                 
888                 /* read shader name */
889                 GetToken( qfalse );
890                 strcpy( name, token );
891                 
892                 /* bp */
893                 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
894                 {
895                         GetToken( qfalse );
896                         shift[ 0 ] = atof( token );
897                         GetToken( qfalse );
898                         shift[ 1 ] = atof( token );
899                         GetToken( qfalse );
900                         rotate = atof( token ); 
901                         GetToken( qfalse );
902                         scale[ 0 ] = atof( token );
903                         GetToken( qfalse );
904                         scale[ 1 ] = atof( token );
905                 }
906                 
907                 /* set default flags and values */
908                 sprintf( shader, "textures/%s", name );
909                 if( onlyLights )
910                         si = &shaderInfo[ 0 ];
911                 else
912                         si = ShaderInfoForShader( shader );
913                 side->shaderInfo = si;
914                 side->surfaceFlags = si->surfaceFlags;
915                 side->contentFlags = si->contentFlags;
916                 side->compileFlags = si->compileFlags;
917                 side->value = si->value;
918                 
919                 /* ydnar: gs mods: bias texture shift */
920                 if( si->globalTexture == qfalse )
921                 {
922                         shift[ 0 ] -= (floor( shift[ 0 ] / si->shaderWidth ) * si->shaderWidth);
923                         shift[ 1 ] -= (floor( shift[ 1 ] / si->shaderHeight ) * si->shaderHeight);
924                 }
925                 
926                 /*
927                         historically, there are 3 integer values at the end of a brushside line in a .map file.
928                         in quake 3, the only thing that mattered was the first of these three values, which
929                         was previously the content flags. and only then did a single bit matter, the detail
930                         bit. because every game has its own special flags for specifying detail, the
931                         traditionally game-specified CONTENTS_DETAIL flag was overridden for Q3Map 2.3.0
932                         by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but
933                         is stored in compileFlags, as opposed to contentFlags, for multiple-game
934                         portability. :sigh:
935                 */
936                 
937                 if( TokenAvailable() )
938                 {
939                         /* get detail bit from map content flags */
940                         GetToken( qfalse );
941                         flags = atoi( token );
942                         if( flags & C_DETAIL )
943                                 side->compileFlags |= C_DETAIL;
944                         
945                         /* historical */
946                         GetToken( qfalse );
947                         //% td.flags = atoi( token );
948                         GetToken( qfalse );
949                         //% td.value = atoi( token );
950                 }
951                 
952                 /* find the plane number */
953                 planenum = MapPlaneFromPoints( planePoints );
954                 side->planenum = planenum;
955                 
956                 /* bp: get the texture mapping for this texturedef / plane combination */
957                 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
958                         QuakeTextureVecs( &mapplanes[ planenum ], shift, rotate, scale, side->vecs );
959         }
960         
961         /* bp */
962         if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
963         {
964                 UnGetToken();
965                 MatchToken( "}" );
966                 MatchToken( "}" );
967         }
968 }
969
970
971
972 /*
973 RemoveDuplicateBrushPlanes
974 returns false if the brush has a mirrored set of planes,
975 meaning it encloses no volume.
976 also removes planes without any normal
977 */
978
979 qboolean RemoveDuplicateBrushPlanes( brush_t *b )
980 {
981         int                     i, j, k;
982         side_t          *sides;
983
984         sides = b->sides;
985
986         for ( i = 1 ; i < b->numsides ; i++ ) {
987
988                 // check for a degenerate plane
989                 if ( sides[i].planenum == -1) {
990                   xml_Select( "degenerate plane", b->entityNum, b->brushNum, qfalse );
991                         // remove it
992                         for ( k = i + 1 ; k < b->numsides ; k++ ) {
993                                 sides[k-1] = sides[k];
994                         }
995                         b->numsides--;
996                         i--;
997                         continue;
998                 }
999
1000                 // check for duplication and mirroring
1001                 for ( j = 0 ; j < i ; j++ ) {
1002                         if ( sides[i].planenum == sides[j].planenum ) {
1003                           xml_Select( "duplicate plane", b->entityNum, b->brushNum, qfalse );
1004                                 // remove the second duplicate
1005                                 for ( k = i + 1 ; k < b->numsides ; k++ ) {
1006                                         sides[k-1] = sides[k];
1007                                 }
1008                                 b->numsides--;
1009                                 i--;
1010                                 break;
1011                         }
1012
1013                         if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
1014                                 // mirror plane, brush is invalid
1015                           xml_Select( "mirrored plane", b->entityNum, b->brushNum, qfalse );
1016                                 return qfalse;
1017                         }
1018                 }
1019         }
1020         return qtrue;
1021 }
1022
1023
1024
1025 /*
1026 ParseBrush()
1027 parses a brush out of a map file and sets it up
1028 */
1029
1030 static void ParseBrush( qboolean onlyLights )
1031 {
1032         brush_t *b;
1033         
1034         
1035         /* parse the brush out of the map */
1036         ParseRawBrush( onlyLights );
1037         
1038         /* only go this far? */
1039         if( onlyLights )
1040                 return;
1041         
1042         /* set some defaults */
1043         buildBrush->portalareas[ 0 ] = -1;
1044         buildBrush->portalareas[ 1 ] = -1;
1045         buildBrush->entityNum = numMapEntities - 1;
1046         buildBrush->brushNum = entitySourceBrushes;
1047         
1048         /* if there are mirrored planes, the entire brush is invalid */
1049         if( !RemoveDuplicateBrushPlanes( buildBrush ) )
1050                 return;
1051         
1052         /* get the content for the entire brush */
1053         SetBrushContents( buildBrush );
1054         
1055         /* allow detail brushes to be removed */
1056         if( nodetail && (buildBrush->compileFlags & C_DETAIL) )
1057         {
1058                 //%     FreeBrush( buildBrush );
1059                 return;
1060         }
1061         
1062         /* allow liquid brushes to be removed */
1063         if( nowater && (buildBrush->compileFlags & C_LIQUID ) )
1064         {
1065                 //%     FreeBrush( buildBrush );
1066                 return;
1067         }
1068         
1069         /* ydnar: allow hint brushes to be removed */
1070         if( noHint && (buildBrush->compileFlags & C_HINT) )
1071         {
1072                 //%     FreeBrush( buildBrush );
1073                 return;
1074         }
1075         
1076         /* finish the brush */
1077         b = FinishBrush();
1078 }
1079
1080
1081
1082 /*
1083 MoveBrushesToWorld()
1084 takes all of the brushes from the current entity and
1085 adds them to the world's brush list
1086 (used by func_group)
1087 */
1088
1089 void AdjustBrushesForOrigin( entity_t *ent );
1090 void MoveBrushesToWorld( entity_t *ent )
1091 {
1092         brush_t         *b, *next;
1093         parseMesh_t     *pm;
1094
1095         /* we need to undo the common/origin adjustment, and instead shift them by the entity key origin */
1096         VectorScale(ent->origin, -1, ent->originbrush_origin);
1097         AdjustBrushesForOrigin(ent);
1098         VectorClear(ent->originbrush_origin);
1099         
1100         /* move brushes */
1101         for( b = ent->brushes; b != NULL; b = next )
1102         {
1103                 /* get next brush */
1104                 next = b->next;
1105                 
1106                 /* link opaque brushes to head of list, translucent brushes to end */
1107                 if( b->opaque || entities[ 0 ].lastBrush == NULL )
1108                 {
1109                         b->next = entities[ 0 ].brushes;
1110                         entities[ 0 ].brushes = b;
1111                         if( entities[ 0 ].lastBrush == NULL )
1112                                 entities[ 0 ].lastBrush = b;
1113                 }
1114                 else
1115                 {
1116                         b->next = NULL;
1117                         entities[ 0 ].lastBrush->next = b;
1118                         entities[ 0 ].lastBrush = b;
1119                 }
1120         }
1121         ent->brushes = NULL;
1122         
1123         /* ydnar: move colormod brushes */
1124         if( ent->colorModBrushes != NULL )
1125         {
1126                 for( b = ent->colorModBrushes; b->nextColorModBrush != NULL; b = b->nextColorModBrush );
1127                 
1128                 b->nextColorModBrush = entities[ 0 ].colorModBrushes;
1129                 entities[ 0 ].colorModBrushes = ent->colorModBrushes;
1130                 
1131                 ent->colorModBrushes = NULL;
1132         }
1133         
1134         /* move patches */
1135         if( ent->patches != NULL )
1136         {
1137                 for( pm = ent->patches; pm->next != NULL; pm = pm->next );
1138                 
1139                 pm->next = entities[ 0 ].patches;
1140                 entities[ 0 ].patches = ent->patches;
1141                 
1142                 ent->patches = NULL;
1143         }
1144 }
1145
1146
1147
1148 /*
1149 AdjustBrushesForOrigin()
1150 */
1151
1152 void AdjustBrushesForOrigin( entity_t *ent )
1153 {
1154         
1155         int                     i;
1156         side_t          *s;
1157         vec_t           newdist;
1158         brush_t         *b;
1159         parseMesh_t     *p;
1160         
1161         /* walk brush list */
1162         for( b = ent->brushes; b != NULL; b = b->next )
1163         {
1164                 /* offset brush planes */
1165                 for( i = 0; i < b->numsides; i++)
1166                 {
1167                         /* get brush side */
1168                         s = &b->sides[ i ];
1169                         
1170                         /* offset side plane */
1171                         newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->originbrush_origin );
1172                         
1173                         /* find a new plane */
1174                         s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1175                 }
1176                 
1177                 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1178                 CreateBrushWindings( b );
1179         }
1180         
1181         /* walk patch list */
1182         for( p = ent->patches; p != NULL; p = p->next )
1183         {
1184                 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1185                         VectorSubtract( p->mesh.verts[ i ].xyz, ent->originbrush_origin, p->mesh.verts[ i ].xyz );
1186         }
1187 }
1188
1189
1190
1191 /*
1192 SetEntityBounds() - ydnar
1193 finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1194 */
1195
1196 void SetEntityBounds( entity_t *e )
1197 {
1198         int                     i;
1199         brush_t *b;
1200         parseMesh_t     *p;
1201         vec3_t          mins, maxs;
1202         const char      *value;
1203
1204         
1205         
1206
1207         /* walk the entity's brushes/patches and determine bounds */
1208         ClearBounds( mins, maxs );
1209         for( b = e->brushes; b; b = b->next )
1210         {
1211                 AddPointToBounds( b->mins, mins, maxs );
1212                 AddPointToBounds( b->maxs, mins, maxs );
1213         }
1214         for( p = e->patches; p; p = p->next )
1215         {
1216                 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1217                         AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1218         }
1219         
1220         /* try to find explicit min/max key */
1221         value = ValueForKey( e, "min" ); 
1222         if( value[ 0 ] != '\0' )
1223                 GetVectorForKey( e, "min", mins );
1224         value = ValueForKey( e, "max" ); 
1225         if( value[ 0 ] != '\0' )
1226                 GetVectorForKey( e, "max", maxs );
1227         
1228         /* store the bounds */
1229         for( b = e->brushes; b; b = b->next )
1230         {
1231                 VectorCopy( mins, b->eMins );
1232                 VectorCopy( maxs, b->eMaxs );
1233         }
1234         for( p = e->patches; p; p = p->next )
1235         {
1236                 VectorCopy( mins, p->eMins );
1237                 VectorCopy( maxs, p->eMaxs );
1238         }
1239 }
1240
1241
1242
1243 /*
1244 LoadEntityIndexMap() - ydnar
1245 based on LoadAlphaMap() from terrain.c, a little more generic
1246 */
1247
1248 void LoadEntityIndexMap( entity_t *e )
1249 {
1250         int                             i, size, numLayers, w, h;
1251         const char              *value, *indexMapFilename, *shader;
1252         char                    ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1253         byte                    *pixels;
1254         unsigned int    *pixels32;
1255         indexMap_t              *im;
1256         brush_t                 *b;
1257         parseMesh_t             *p;
1258         
1259         
1260         /* this only works with bmodel ents */
1261         if( e->brushes == NULL && e->patches == NULL )
1262                 return;
1263         
1264         /* determine if there is an index map (support legacy "alphamap" key as well) */
1265         value = ValueForKey( e, "_indexmap" );
1266         if( value[ 0 ] == '\0' )
1267                 value = ValueForKey( e, "alphamap" );
1268         if( value[ 0 ] == '\0' )
1269                 return;
1270         indexMapFilename = value;
1271         
1272         /* get number of layers (support legacy "layers" key as well) */
1273         value = ValueForKey( e, "_layers" );
1274         if( value[ 0 ] == '\0' )
1275                 value = ValueForKey( e, "layers" );
1276         if( value[ 0 ] == '\0' )
1277         {
1278                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1279                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1280                 return;
1281         }
1282         numLayers = atoi( value );
1283         if( numLayers < 1 )
1284         {
1285                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1286                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1287                 return;
1288         }
1289         
1290         /* get base shader name (support legacy "shader" key as well) */
1291         value = ValueForKey( mapEnt, "_shader" );
1292         if( value[ 0 ] == '\0' )
1293                 value = ValueForKey( e, "shader" );
1294         if( value[ 0 ] == '\0' )
1295         {
1296                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1297                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1298                 return;
1299         }
1300         shader = value;
1301         
1302         /* note it */
1303         Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n",  mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1304         
1305         /* get index map file extension */
1306         ExtractFileExtension( indexMapFilename, ext );
1307         
1308         /* handle tga image */
1309         if( !Q_stricmp( ext, "tga" ) )
1310         {
1311                 /* load it */
1312                 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1313                 
1314                 /* convert to bytes */
1315                 size = w * h;
1316                 pixels = safe_malloc( size );
1317                 for( i = 0; i < size; i++ )
1318                 {
1319                         pixels[ i ] = ((pixels32[ i ] & 0xFF) * numLayers) / 256;
1320                         if( pixels[ i ] >= numLayers )
1321                                 pixels[ i ] = numLayers - 1;
1322                 }
1323                 
1324                 /* free the 32 bit image */
1325                 free( pixels32 );
1326         }
1327         else
1328         {
1329                 /* load it */
1330                 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1331                 
1332                 /* debug code */
1333                 //%     Sys_Printf( "-------------------------------" );
1334                 
1335                 /* fix up out-of-range values */
1336                 size = w * h;
1337                 for( i = 0; i < size; i++ )
1338                 {
1339                         if( pixels[ i ] >= numLayers )
1340                                 pixels[ i ] = numLayers - 1;
1341                         
1342                         /* debug code */
1343                         //%     if( (i % w) == 0 )
1344                         //%             Sys_Printf( "\n" );
1345                         //%     Sys_Printf( "%c", pixels[ i ] + '0' );
1346                 }
1347                 
1348                 /* debug code */
1349                 //%     Sys_Printf( "\n-------------------------------\n" );
1350         }
1351         
1352         /* the index map must be at least 2x2 pixels */
1353         if( w < 2 || h < 2 )
1354         {
1355                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1356                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1357                 free( pixels );
1358                 return;
1359         }
1360
1361         /* create a new index map */
1362         im = safe_malloc( sizeof( *im ) );
1363         memset( im, 0, sizeof( *im ) );
1364         
1365         /* set it up */
1366         im->w = w;
1367         im->h = h;
1368         im->numLayers = numLayers;
1369         strcpy( im->name, indexMapFilename );
1370         strcpy( im->shader, shader );
1371         im->pixels = pixels;
1372         
1373         /* get height offsets */
1374         value = ValueForKey( mapEnt, "_offsets" );
1375         if( value[ 0 ] == '\0' )
1376                 value = ValueForKey( e, "offsets" );
1377         if( value[ 0 ] != '\0' )
1378         {
1379                 /* value is a space-seperated set of numbers */
1380                 strcpy( offset, value );
1381                 search = offset;
1382                 
1383                 /* get each value */
1384                 for( i = 0; i < 256 && *search != '\0'; i++ )
1385                 {
1386                         space = strstr( search, " " );
1387                         if( space != NULL )
1388                                 *space = '\0';
1389                         im->offsets[ i ] = atof( search );
1390                         if( space == NULL )
1391                                 break;
1392                         search = space + 1;
1393                 }
1394         }
1395         
1396         /* store the index map in every brush/patch in the entity */
1397         for( b = e->brushes; b != NULL; b = b->next )
1398                 b->im = im;
1399         for( p = e->patches; p != NULL; p = p->next )
1400                 p->im = im;
1401 }
1402
1403
1404
1405
1406
1407
1408
1409 /*
1410 ParseMapEntity()
1411 parses a single entity out of a map file
1412 */
1413
1414 static qboolean ParseMapEntity( qboolean onlyLights )
1415 {
1416         epair_t                 *ep;
1417         const char              *classname, *value;
1418         float                   lightmapScale;
1419         char                    shader[ MAX_QPATH ];
1420         shaderInfo_t    *celShader = NULL;
1421         brush_t                 *brush;
1422         parseMesh_t             *patch;
1423         qboolean                funcGroup;
1424         int                             castShadows, recvShadows;
1425         
1426         
1427         /* eof check */
1428         if( !GetToken( qtrue ) )
1429                 return qfalse;
1430         
1431         /* conformance check */
1432         if( strcmp( token, "{" ) )
1433         {
1434                 Sys_Printf( "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1435                         "Continuing to process map, but resulting BSP may be invalid.\n",
1436                         token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1437                 return qfalse;
1438         }
1439         
1440         /* range check */
1441         if( numEntities >= MAX_MAP_ENTITIES )
1442                 Error( "numEntities == MAX_MAP_ENTITIES" );
1443         
1444         /* setup */
1445         entitySourceBrushes = 0;
1446         mapEnt = &entities[ numEntities ];
1447         numEntities++;
1448         memset( mapEnt, 0, sizeof( *mapEnt ) );
1449         
1450         /* ydnar: true entity numbering */
1451         mapEnt->mapEntityNum = numMapEntities;
1452         numMapEntities++;
1453         
1454         /* loop */
1455         while( 1 )
1456         {
1457                 /* get initial token */
1458                 if( !GetToken( qtrue ) )
1459                 {
1460                         Sys_Printf( "WARNING: ParseEntity: EOF without closing brace\n"
1461                                 "Continuing to process map, but resulting BSP may be invalid.\n" );
1462                         return qfalse;
1463                 }
1464                 
1465                 if( !strcmp( token, "}" ) )
1466                         break;
1467                 
1468                 if( !strcmp( token, "{" ) )
1469                 {
1470                         /* parse a brush or patch */
1471                         if( !GetToken( qtrue ) )
1472                                 break;
1473                         
1474                         /* check */
1475                         if( !strcmp( token, "patchDef2" ) )
1476                         {
1477                                 numMapPatches++;
1478                                 ParsePatch( onlyLights );
1479                         }
1480                         else if( !strcmp( token, "terrainDef" ) )
1481                         {
1482                                 //% ParseTerrain();
1483                                 Sys_Printf( "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1484                         }
1485                         else if( !strcmp( token, "brushDef" ) )
1486                         {
1487                                 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1488                                         Error( "Old brush format not allowed in new brush format map" );
1489                                 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1490                                 
1491                                 /* parse brush primitive */
1492                                 ParseBrush( onlyLights );
1493                         }
1494                         else
1495                         {
1496                                 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1497                                         Error( "New brush format not allowed in old brush format map" );
1498                                 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1499                                 
1500                                 /* parse old brush format */
1501                                 UnGetToken();
1502                                 ParseBrush( onlyLights );
1503                         }
1504                         entitySourceBrushes++;
1505                 }
1506                 else
1507                 {
1508                         /* parse a key / value pair */
1509                         ep = ParseEPair();
1510                         
1511                         /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1512                         if( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' )
1513                         {
1514                                 ep->next = mapEnt->epairs;
1515                                 mapEnt->epairs = ep;
1516                         }
1517                 }
1518         }
1519         
1520         /* ydnar: get classname */
1521         classname = ValueForKey( mapEnt, "classname" );
1522         
1523         /* ydnar: only lights? */
1524         if( onlyLights && Q_strncasecmp( classname, "light", 5 ) )
1525         {
1526                 numEntities--;
1527                 return qtrue;
1528         }
1529         
1530         /* ydnar: determine if this is a func_group */
1531         if( !Q_stricmp( "func_group", classname ) )
1532                 funcGroup = qtrue;
1533         else
1534                 funcGroup = qfalse;
1535         
1536         /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1537         if( funcGroup || mapEnt->mapEntityNum == 0 )
1538         {
1539                 //%     Sys_Printf( "World:  %d\n", mapEnt->mapEntityNum );
1540                 castShadows = WORLDSPAWN_CAST_SHADOWS;
1541                 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1542         }
1543         
1544         /* other entities don't cast any shadows, but recv worldspawn shadows */
1545         else
1546         {
1547                 //%     Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1548                 castShadows = ENTITY_CAST_SHADOWS;
1549                 recvShadows = ENTITY_RECV_SHADOWS;
1550         }
1551         
1552         /* get explicit shadow flags */
1553         GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1554         
1555         /* vortex: added _ls key (short name of lightmapscale) */
1556         /* ydnar: get lightmap scaling value for this entity */
1557         if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1558                 strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) || 
1559                 strcmp( "", ValueForKey( mapEnt, "_ls" ) ) )
1560         {
1561                 /* get lightmap scale from entity */
1562                 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1563                 if( lightmapScale <= 0.0f )
1564                         lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1565                 if( lightmapScale <= 0.0f )
1566                         lightmapScale = FloatForKey( mapEnt, "_ls" );
1567                 if( lightmapScale > 0.0f )
1568                         Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1569         }
1570         else
1571                 lightmapScale = 0.0f;
1572         
1573         /* ydnar: get cel shader :) for this entity */
1574         value = ValueForKey( mapEnt, "_celshader" );
1575         if( value[ 0 ] == '\0' )        
1576                 value = ValueForKey( &entities[ 0 ], "_celshader" );
1577         if( value[ 0 ] != '\0' )
1578         {
1579                 sprintf( shader, "textures/%s", value );
1580                 celShader = ShaderInfoForShader( shader );
1581                 Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1582         }
1583         else
1584                 celShader = *globalCelShader ? ShaderInfoForShader(globalCelShader) : NULL;
1585         
1586         /* attach stuff to everything in the entity */
1587         for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1588         {
1589                 brush->entityNum = mapEnt->mapEntityNum;
1590                 brush->castShadows = castShadows;
1591                 brush->recvShadows = recvShadows;
1592                 brush->lightmapScale = lightmapScale;
1593                 brush->celShader = celShader;
1594         }
1595         
1596         for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1597         {
1598                 patch->entityNum = mapEnt->mapEntityNum;
1599                 patch->castShadows = castShadows;
1600                 patch->recvShadows = recvShadows;
1601                 patch->lightmapScale = lightmapScale;
1602                 patch->celShader = celShader;
1603         }
1604         
1605         /* ydnar: gs mods: set entity bounds */
1606         SetEntityBounds( mapEnt );
1607         
1608         /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1609         LoadEntityIndexMap( mapEnt );
1610         
1611         /* get entity origin and adjust brushes */
1612         GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1613         if( mapEnt->originbrush_origin[ 0 ] || mapEnt->originbrush_origin[ 1 ] || mapEnt->originbrush_origin[ 2 ] )
1614                 AdjustBrushesForOrigin( mapEnt );
1615
1616         /* group_info entities are just for editor grouping (fixme: leak!) */
1617         if( !Q_stricmp( "group_info", classname ) )
1618         {
1619                 numEntities--;
1620                 return qtrue;
1621         }
1622         
1623         /* group entities are just for editor convenience, toss all brushes into worldspawn */
1624         if( funcGroup )
1625         {
1626                 MoveBrushesToWorld( mapEnt );
1627                 numEntities--;
1628                 return qtrue;
1629         }
1630         
1631         /* done */
1632         return qtrue;
1633 }
1634
1635
1636
1637 /*
1638 LoadMapFile()
1639 loads a map file into a list of entities
1640 */
1641
1642 void LoadMapFile( char *filename, qboolean onlyLights )
1643 {               
1644         FILE            *file;
1645         brush_t         *b;
1646         int                     oldNumEntities, numMapBrushes;
1647         
1648         
1649         /* note it */
1650         Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1651         Sys_Printf( "Loading %s\n", filename );
1652         
1653         /* hack */
1654         file = SafeOpenRead( filename );
1655         fclose( file );
1656         
1657         /* load the map file */
1658         LoadScriptFile( filename, -1 );
1659         
1660         /* setup */
1661         if( onlyLights )
1662                 oldNumEntities = numEntities;
1663         else
1664                 numEntities = 0;
1665         
1666         /* initial setup */
1667         numMapDrawSurfs = 0;
1668         c_detail = 0;
1669         g_bBrushPrimit = BPRIMIT_UNDEFINED;
1670         
1671         /* allocate a very large temporary brush for building the brushes as they are loaded */
1672         buildBrush = AllocBrush( MAX_BUILD_SIDES );
1673         
1674         /* parse the map file */
1675         while( ParseMapEntity( onlyLights ) );
1676         
1677         /* light loading */
1678         if( onlyLights )
1679         {
1680                 /* emit some statistics */
1681                 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1682         }
1683         else
1684         {
1685                 /* set map bounds */
1686                 ClearBounds( mapMins, mapMaxs );
1687                 for( b = entities[ 0 ].brushes; b; b = b->next )
1688                 {
1689                         AddPointToBounds( b->mins, mapMins, mapMaxs );
1690                         AddPointToBounds( b->maxs, mapMins, mapMaxs );
1691                 }
1692                 
1693                 /* get brush counts */
1694                 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1695                 if( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 )
1696                         Sys_Printf( "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1697                 
1698                 /* emit some statistics */
1699                 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1700                 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1701                 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches);
1702                 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels);
1703                 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels);
1704                 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1705                 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes);
1706                 Sys_Printf( "%9d areaportals\n", c_areaportals);
1707                 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1708                         mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1709                         mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ]);
1710                 
1711                 /* write bogus map */
1712                 if( fakemap )
1713                         WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );
1714         }
1715 }