]> git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/map.c
IGNORE: whitespace-only changes
[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         /* walk brush list */
1284         for( b = ent->brushes; b != NULL; b = b->next )
1285         {
1286                 /* offset brush planes */
1287                 for( i = 0; i < b->numsides; i++)
1288                 {
1289                         /* get brush side */
1290                         s = &b->sides[ i ];
1291                         
1292                         /* offset side plane */
1293                         newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->origin );
1294                         
1295                         /* find a new plane */
1296                         s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1297                 }
1298                 
1299                 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1300                 CreateBrushWindings( b );
1301         }
1302         
1303         /* walk patch list */
1304         for( p = ent->patches; p != NULL; p = p->next )
1305         {
1306                 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1307                         VectorSubtract( p->mesh.verts[ i ].xyz, ent->origin, p->mesh.verts[ i ].xyz );
1308         }
1309 }
1310
1311
1312
1313 /*
1314 SetEntityBounds() - ydnar
1315 finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1316 */
1317
1318 void SetEntityBounds( entity_t *e )
1319 {
1320         int                     i;
1321         brush_t *b;
1322         parseMesh_t     *p;
1323         vec3_t          mins, maxs;
1324         const char      *value;
1325
1326         
1327         
1328
1329         /* walk the entity's brushes/patches and determine bounds */
1330         ClearBounds( mins, maxs );
1331         for( b = e->brushes; b; b = b->next )
1332         {
1333                 AddPointToBounds( b->mins, mins, maxs );
1334                 AddPointToBounds( b->maxs, mins, maxs );
1335         }
1336         for( p = e->patches; p; p = p->next )
1337         {
1338                 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1339                         AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1340         }
1341         
1342         /* try to find explicit min/max key */
1343         value = ValueForKey( e, "min" ); 
1344         if( value[ 0 ] != '\0' )
1345                 GetVectorForKey( e, "min", mins );
1346         value = ValueForKey( e, "max" ); 
1347         if( value[ 0 ] != '\0' )
1348                 GetVectorForKey( e, "max", maxs );
1349         
1350         /* store the bounds */
1351         for( b = e->brushes; b; b = b->next )
1352         {
1353                 VectorCopy( mins, b->eMins );
1354                 VectorCopy( maxs, b->eMaxs );
1355         }
1356         for( p = e->patches; p; p = p->next )
1357         {
1358                 VectorCopy( mins, p->eMins );
1359                 VectorCopy( maxs, p->eMaxs );
1360         }
1361 }
1362
1363
1364
1365 /*
1366 LoadEntityIndexMap() - ydnar
1367 based on LoadAlphaMap() from terrain.c, a little more generic
1368 */
1369
1370 void LoadEntityIndexMap( entity_t *e )
1371 {
1372         int                             i, size, numLayers, w, h;
1373         const char              *value, *indexMapFilename, *shader;
1374         char                    ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1375         byte                    *pixels;
1376         unsigned int    *pixels32;
1377         indexMap_t              *im;
1378         brush_t                 *b;
1379         parseMesh_t             *p;
1380         
1381         
1382         /* this only works with bmodel ents */
1383         if( e->brushes == NULL && e->patches == NULL )
1384                 return;
1385         
1386         /* determine if there is an index map (support legacy "alphamap" key as well) */
1387         value = ValueForKey( e, "_indexmap" );
1388         if( value[ 0 ] == '\0' )
1389                 value = ValueForKey( e, "alphamap" );
1390         if( value[ 0 ] == '\0' )
1391                 return;
1392         indexMapFilename = value;
1393         
1394         /* get number of layers (support legacy "layers" key as well) */
1395         value = ValueForKey( e, "_layers" );
1396         if( value[ 0 ] == '\0' )
1397                 value = ValueForKey( e, "layers" );
1398         if( value[ 0 ] == '\0' )
1399         {
1400                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1401                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1402                 return;
1403         }
1404         numLayers = atoi( value );
1405         if( numLayers < 1 )
1406         {
1407                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1408                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1409                 return;
1410         }
1411         
1412         /* get base shader name (support legacy "shader" key as well) */
1413         value = ValueForKey( mapEnt, "_shader" );
1414         if( value[ 0 ] == '\0' )
1415                 value = ValueForKey( e, "shader" );
1416         if( value[ 0 ] == '\0' )
1417         {
1418                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1419                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1420                 return;
1421         }
1422         shader = value;
1423         
1424         /* note it */
1425         Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n",  mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1426         
1427         /* get index map file extension */
1428         ExtractFileExtension( indexMapFilename, ext );
1429         
1430         /* handle tga image */
1431         if( !Q_stricmp( ext, "tga" ) )
1432         {
1433                 /* load it */
1434                 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1435                 
1436                 /* convert to bytes */
1437                 size = w * h;
1438                 pixels = safe_malloc( size );
1439                 for( i = 0; i < size; i++ )
1440                 {
1441                         pixels[ i ] = ((pixels32[ i ] & 0xFF) * numLayers) / 256;
1442                         if( pixels[ i ] >= numLayers )
1443                                 pixels[ i ] = numLayers - 1;
1444                 }
1445                 
1446                 /* free the 32 bit image */
1447                 free( pixels32 );
1448         }
1449         else
1450         {
1451                 /* load it */
1452                 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1453                 
1454                 /* debug code */
1455                 //%     Sys_Printf( "-------------------------------" );
1456                 
1457                 /* fix up out-of-range values */
1458                 size = w * h;
1459                 for( i = 0; i < size; i++ )
1460                 {
1461                         if( pixels[ i ] >= numLayers )
1462                                 pixels[ i ] = numLayers - 1;
1463                         
1464                         /* debug code */
1465                         //%     if( (i % w) == 0 )
1466                         //%             Sys_Printf( "\n" );
1467                         //%     Sys_Printf( "%c", pixels[ i ] + '0' );
1468                 }
1469                 
1470                 /* debug code */
1471                 //%     Sys_Printf( "\n-------------------------------\n" );
1472         }
1473         
1474         /* the index map must be at least 2x2 pixels */
1475         if( w < 2 || h < 2 )
1476         {
1477                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1478                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1479                 free( pixels );
1480                 return;
1481         }
1482
1483         /* create a new index map */
1484         im = safe_malloc( sizeof( *im ) );
1485         memset( im, 0, sizeof( *im ) );
1486         
1487         /* set it up */
1488         im->w = w;
1489         im->h = h;
1490         im->numLayers = numLayers;
1491         strcpy( im->name, indexMapFilename );
1492         strcpy( im->shader, shader );
1493         im->pixels = pixels;
1494         
1495         /* get height offsets */
1496         value = ValueForKey( mapEnt, "_offsets" );
1497         if( value[ 0 ] == '\0' )
1498                 value = ValueForKey( e, "offsets" );
1499         if( value[ 0 ] != '\0' )
1500         {
1501                 /* value is a space-seperated set of numbers */
1502                 strcpy( offset, value );
1503                 search = offset;
1504                 
1505                 /* get each value */
1506                 for( i = 0; i < 256 && *search != '\0'; i++ )
1507                 {
1508                         space = strstr( search, " " );
1509                         if( space != NULL )
1510                                 *space = '\0';
1511                         im->offsets[ i ] = atof( search );
1512                         if( space == NULL )
1513                                 break;
1514                         search = space + 1;
1515                 }
1516         }
1517         
1518         /* store the index map in every brush/patch in the entity */
1519         for( b = e->brushes; b != NULL; b = b->next )
1520                 b->im = im;
1521         for( p = e->patches; p != NULL; p = p->next )
1522                 p->im = im;
1523 }
1524
1525
1526
1527
1528
1529
1530
1531 /*
1532 ParseMapEntity()
1533 parses a single entity out of a map file
1534 */
1535
1536 static qboolean ParseMapEntity( qboolean onlyLights )
1537 {
1538         epair_t                 *ep;
1539         const char              *classname, *value;
1540         float                   lightmapScale;
1541         char                    shader[ MAX_QPATH ];
1542         shaderInfo_t    *celShader = NULL;
1543         brush_t                 *brush;
1544         parseMesh_t             *patch;
1545         qboolean                funcGroup;
1546         int                             castShadows, recvShadows;
1547         
1548         
1549         /* eof check */
1550         if( !GetToken( qtrue ) )
1551                 return qfalse;
1552         
1553         /* conformance check */
1554         if( strcmp( token, "{" ) )
1555         {
1556                 Sys_Printf( "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1557                         "Continuing to process map, but resulting BSP may be invalid.\n",
1558                         token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1559                 return qfalse;
1560         }
1561         
1562         /* range check */
1563         if( numEntities >= MAX_MAP_ENTITIES )
1564                 Error( "numEntities == MAX_MAP_ENTITIES" );
1565         
1566         /* setup */
1567         entitySourceBrushes = 0;
1568         mapEnt = &entities[ numEntities ];
1569         numEntities++;
1570         memset( mapEnt, 0, sizeof( *mapEnt ) );
1571         
1572         /* ydnar: true entity numbering */
1573         mapEnt->mapEntityNum = numMapEntities;
1574         numMapEntities++;
1575         
1576         /* loop */
1577         while( 1 )
1578         {
1579                 /* get initial token */
1580                 if( !GetToken( qtrue ) )
1581                 {
1582                         Sys_Printf( "WARNING: ParseEntity: EOF without closing brace\n"
1583                                 "Continuing to process map, but resulting BSP may be invalid.\n" );
1584                         return qfalse;
1585                 }
1586                 
1587                 if( !strcmp( token, "}" ) )
1588                         break;
1589                 
1590                 if( !strcmp( token, "{" ) )
1591                 {
1592                         /* parse a brush or patch */
1593                         if( !GetToken( qtrue ) )
1594                                 break;
1595                         
1596                         /* check */
1597                         if( !strcmp( token, "patchDef2" ) )
1598                         {
1599                                 numMapPatches++;
1600                                 ParsePatch( onlyLights );
1601                         }
1602                         else if( !strcmp( token, "terrainDef" ) )
1603                         {
1604                                 //% ParseTerrain();
1605                                 Sys_Printf( "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1606                         }
1607                         else if( !strcmp( token, "brushDef" ) )
1608                         {
1609                                 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1610                                         Error( "Old brush format not allowed in new brush format map" );
1611                                 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1612                                 
1613                                 /* parse brush primitive */
1614                                 ParseBrush( onlyLights );
1615                         }
1616                         else
1617                         {
1618                                 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1619                                         Error( "New brush format not allowed in old brush format map" );
1620                                 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1621                                 
1622                                 /* parse old brush format */
1623                                 UnGetToken();
1624                                 ParseBrush( onlyLights );
1625                         }
1626                         entitySourceBrushes++;
1627                 }
1628                 else
1629                 {
1630                         /* parse a key / value pair */
1631                         ep = ParseEPair();
1632                         
1633                         /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1634                         if( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' )
1635                         {
1636                                 ep->next = mapEnt->epairs;
1637                                 mapEnt->epairs = ep;
1638                         }
1639                 }
1640         }
1641         
1642         /* ydnar: get classname */
1643         classname = ValueForKey( mapEnt, "classname" );
1644         
1645         /* ydnar: only lights? */
1646         if( onlyLights && Q_strncasecmp( classname, "light", 5 ) )
1647         {
1648                 numEntities--;
1649                 return qtrue;
1650         }
1651         
1652         /* ydnar: determine if this is a func_group */
1653         if( !Q_stricmp( "func_group", classname ) )
1654                 funcGroup = qtrue;
1655         else
1656                 funcGroup = qfalse;
1657         
1658         /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1659         if( funcGroup || mapEnt->mapEntityNum == 0 )
1660         {
1661                 //%     Sys_Printf( "World:  %d\n", mapEnt->mapEntityNum );
1662                 castShadows = WORLDSPAWN_CAST_SHADOWS;
1663                 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1664         }
1665         
1666         /* other entities don't cast any shadows, but recv worldspawn shadows */
1667         else
1668         {
1669                 //%     Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1670                 castShadows = ENTITY_CAST_SHADOWS;
1671                 recvShadows = ENTITY_RECV_SHADOWS;
1672         }
1673         
1674         /* get explicit shadow flags */
1675         GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1676         
1677         /* ydnar: get lightmap scaling value for this entity */
1678         if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1679                 strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) )
1680         {
1681                 /* get lightmap scale from entity */
1682                 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1683                 if( lightmapScale <= 0.0f )
1684                         lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1685                 if( lightmapScale > 0.0f )
1686                         Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1687         }
1688         else
1689                 lightmapScale = 0.0f;
1690         
1691         /* ydnar: get cel shader :) for this entity */
1692         value = ValueForKey( mapEnt, "_celshader" );
1693         if( value[ 0 ] == '\0' )        
1694                 value = ValueForKey( &entities[ 0 ], "_celshader" );
1695         if( value[ 0 ] != '\0' )
1696         {
1697                 sprintf( shader, "textures/%s", value );
1698                 celShader = ShaderInfoForShader( shader );
1699                 Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1700         }
1701         else
1702                 celShader = NULL;
1703         
1704         /* attach stuff to everything in the entity */
1705         for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1706         {
1707                 brush->entityNum = mapEnt->mapEntityNum;
1708                 brush->castShadows = castShadows;
1709                 brush->recvShadows = recvShadows;
1710                 brush->lightmapScale = lightmapScale;
1711                 brush->celShader = celShader;
1712         }
1713         
1714         for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1715         {
1716                 patch->entityNum = mapEnt->mapEntityNum;
1717                 patch->castShadows = castShadows;
1718                 patch->recvShadows = recvShadows;
1719                 patch->lightmapScale = lightmapScale;
1720                 patch->celShader = celShader;
1721         }
1722         
1723         /* ydnar: gs mods: set entity bounds */
1724         SetEntityBounds( mapEnt );
1725         
1726         /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1727         LoadEntityIndexMap( mapEnt );
1728         
1729         /* get entity origin and adjust brushes */
1730         GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1731         if( mapEnt->origin[ 0 ] || mapEnt->origin[ 1 ] || mapEnt->origin[ 2 ] )
1732                 AdjustBrushesForOrigin( mapEnt );
1733
1734         /* group_info entities are just for editor grouping (fixme: leak!) */
1735         if( !Q_stricmp( "group_info", classname ) )
1736         {
1737                 numEntities--;
1738                 return qtrue;
1739         }
1740         
1741         /* group entities are just for editor convenience, toss all brushes into worldspawn */
1742         if( funcGroup )
1743         {
1744                 MoveBrushesToWorld( mapEnt );
1745                 numEntities--;
1746                 return qtrue;
1747         }
1748         
1749         /* done */
1750         return qtrue;
1751 }
1752
1753
1754
1755 /*
1756 LoadMapFile()
1757 loads a map file into a list of entities
1758 */
1759
1760 void LoadMapFile( char *filename, qboolean onlyLights )
1761 {               
1762         FILE            *file;
1763         brush_t         *b;
1764         int                     oldNumEntities, numMapBrushes;
1765         
1766         
1767         /* note it */
1768         Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1769         Sys_Printf( "Loading %s\n", filename );
1770         
1771         /* hack */
1772         file = SafeOpenRead( filename );
1773         fclose( file );
1774         
1775         /* load the map file */
1776         LoadScriptFile( filename, -1 );
1777         
1778         /* setup */
1779         if( onlyLights )
1780                 oldNumEntities = numEntities;
1781         else
1782                 numEntities = 0;
1783         
1784         /* initial setup */
1785         numMapDrawSurfs = 0;
1786         c_detail = 0;
1787         g_bBrushPrimit = BPRIMIT_UNDEFINED;
1788         
1789         /* allocate a very large temporary brush for building the brushes as they are loaded */
1790         buildBrush = AllocBrush( MAX_BUILD_SIDES );
1791         
1792         /* parse the map file */
1793         while( ParseMapEntity( onlyLights ) );
1794         
1795         /* light loading */
1796         if( onlyLights )
1797         {
1798                 /* emit some statistics */
1799                 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1800         }
1801         else
1802         {
1803                 /* set map bounds */
1804                 ClearBounds( mapMins, mapMaxs );
1805                 for( b = entities[ 0 ].brushes; b; b = b->next )
1806                 {
1807                         AddPointToBounds( b->mins, mapMins, mapMaxs );
1808                         AddPointToBounds( b->maxs, mapMins, mapMaxs );
1809                 }
1810                 
1811                 /* get brush counts */
1812                 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1813                 if( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 )
1814                         Sys_Printf( "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1815                 
1816                 /* emit some statistics */
1817                 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1818                 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1819                 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches);
1820                 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels);
1821                 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels);
1822                 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1823                 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes);
1824                 Sys_Printf( "%9d areaportals\n", c_areaportals);
1825                 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1826                         mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1827                         mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ]);
1828                 
1829                 /* write bogus map */
1830                 if( fakemap )
1831                         WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );
1832         }
1833 }