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