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